This commit is contained in:
root
2025-11-25 09:56:15 +03:00
commit 68c8f0e80d
23717 changed files with 3200521 additions and 0 deletions

21
mc_test/node_modules/electron-log/LICENSE generated vendored Executable file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Alexey Prokhorov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

286
mc_test/node_modules/electron-log/README.md generated vendored Executable file
View File

@ -0,0 +1,286 @@
# electron-log
[![Tests](https://github.com/megahertz/electron-log/actions/workflows/tests.yml/badge.svg)](https://github.com/megahertz/electron-log/actions/workflows/tests.yml)
[![NPM version](https://badge.fury.io/js/electron-log.svg)](https://badge.fury.io/js/electron-log)
[![Downloads](https://img.shields.io/npm/dw/electron-log)](https://img.shields.io/npm/dw/electron-log)
Simple logging module Electron/Node.js/NW.js application.
No dependencies. No complicated configuration.
By default, it writes logs to the following locations:
- **on Linux:** `~/.config/{app name}/logs/main.log`
- **on macOS:** `~/Library/Logs/{app name}/main.log`
- **on Windows:** `%USERPROFILE%\AppData\Roaming\{app name}\logs\main.log`
## Installation
Starts from v5, electron-log requires Electron 13+ or
Node.js 14+. Feel free to use electron-log v4 for older runtime. v4
supports Node.js 0.10+ and almost any Electron build.
Install with [npm](https://npmjs.org/package/electron-log):
npm install electron-log
## Usage
### Main process
```js
import log from 'electron-log/main';
// Optional, initialize the logger for any renderer process
log.initialize();
log.info('Log from the main process');
```
### Renderer process
If a bundler is used, you can just import the module:
```typescript
import log from 'electron-log/renderer';
log.info('Log from the renderer process');
```
This function uses sessions to inject a preload script to make the logger
available in a renderer process.
Without a bundler, you can use a global variable `__electronLog`. It contains
only log functions like `info`, `warn` and so on.
There are a few other ways how a logger can be initialized for a renderer
process. [Read more](docs/initialize.md).
### Preload script
To use the logger inside a preload script, use the
`electron-log/renderer` import.
There's also the `electron-log/preload` entrypoint, but it's used only as a
bridge between the main and renderer processes and doesn't export a logger. In
most cases, you don't need this preload entrypoint.
### Node.js and NW.js
```typescript
import log from 'electron-log/node';
log.info('Log from the nw.js or node.js');
```
### electron-log v2.x, v3.x, v4.x
If you would like to upgrade to the latest version, read
[the migration guide](docs/migration.md) and [the changelog](CHANGELOG.md).
### Log levels
electron-log supports the following log levels:
error, warn, info, verbose, debug, silly
### Transport
Transport is a simple function which does some work with log message.
By default, two transports are active: console and file.
You can set transport options or use methods using:
`log.transports.console.format = '{h}:{i}:{s} {text}';`
`log.transports.file.getFile();`
Each transport has `level` and
[`transforms`](docs/extend.md#transforms) options.
#### Console transport
Just prints a log message to application console (main process) or to
DevTools console (renderer process).
##### Options
- **[format](docs/transports/format.md)**, default
`'%c{h}:{i}:{s}.{ms}%c {text}'` (main),
`'{h}:{i}:{s}.{ms} {text}'` (renderer)
- **level**, default 'silly'
- **useStyles**, force enable/disable styles
[Read more about console transport](docs/transports/console.md).
#### File transport
The file transport writes log messages to a file.
##### Options
- **[format](docs/transports/format.md)**, default
`'[{y}-{m}-{d} {h}:{i}:{s}.{ms}] [{level}] {text}'`
- **level**, default 'silly'
- **resolvePathFn** function sets the log path, for example
```js
log.transports.file.resolvePathFn = () => path.join(APP_DATA, 'logs/main.log');
```
[Read more about file transport](docs/transports/file.md).
#### IPC transport
It displays log messages from main process in the renderer's DevTools console.
By default, it's disabled for a production build. You can enable in the
production mode by setting the `level` property.
##### Options
- **level**, default 'silly' in the dev mode, `false` in the production.
#### Remote transport
Sends a JSON POST request with `LogMessage` in the body to the specified url.
##### Options
- **level**, default false
- **url**, remote endpoint
[Read more about remote transport](docs/transports/remote.md).
#### Disable a transport
Just set level property to false, for example:
```js
log.transports.file.level = false;
log.transports.console.level = false;
```
#### [Override/add a custom transport](docs/extend.md#transport)
Transport is just a function `(msg: LogMessage) => void`, so you can
easily override/add your own transport.
[More info](docs/extend.md#transport).
#### Third-party transports
- [Datadog](https://github.com/marklai1998/datadog-logger-integrations)
### Overriding console.log
Sometimes it's helpful to use electron-log instead of default `console`. It's
pretty easy:
```js
console.log = log.log;
```
If you would like to override other functions like `error`, `warn` and so on:
```js
Object.assign(console, log.functions);
```
### Colors
Colors can be used for both main and DevTools console.
`log.info('%cRed text. %cGreen text', 'color: red', 'color: green')`
Available colors:
- unset (reset to default color)
- black
- red
- green
- yellow
- blue
- magenta
- cyan
- white
For DevTools console you can use other CSS properties.
### [Catch errors](docs/errors.md)
electron-log can catch and log unhandled errors/rejected promises:
`log.errorHandler.startCatching(options?)`;
[More info](docs/errors.md).
#### Electron events logging
Sometimes it's helpful to save critical electron events to the log file.
`log.eventLogger.startLogging(options?)`;
By default, it save the following events:
- `certificate-error`, `child-process-gone`, `render-process-gone` of `app`
- `crashed`, `gpu-process-crashed` of `webContents`
- `did-fail-load`, `did-fail-provisional-load`, `plugin-crashed`,
`preload-error` of every WebContents. You can switch any event on/off.
[More info](docs/events.md).
### [Hooks](docs/extend.md#hooks)
In some situations, you may want to get more control over logging. Hook
is a function which is called on each transport call.
`(message: LogMessage, transport: Transport, transportName) => LogMessage`
[More info](docs/extend.md#hooks).
### Multiple logger instances
You can create multiple logger instances with different settings:
```js
import log from 'electron-log/main';
const anotherLogger = log.create({ logId: 'anotherInstance' });
```
Be aware that you need to configure each instance (e.g. log file path)
separately.
### Logging scopes
```js
import log from 'electron-log/main';
const userLog = log.scope('user');
userLog.info('message with user scope');
// Prints 12:12:21.962 (user) message with user scope
```
By default, scope labels are padded in logs. To disable it, set
`log.scope.labelPadding = false`.
### Buffering
It's like a transaction, you may add some logs to the buffer and then decide
whether to write these logs or not. It allows adding verbose logs only
when some operations failed.
```js
import log from 'electron-log/main';
log.buffering.begin();
try {
log.info('First silly message');
// do somethings complex
log.info('Second silly message');
// do something else
// Finished fine, we don't need these logs anymore
log.buffering.reject();
} catch (e) {
log.buffering.commit();
log.warn(e);
}
```
## Related
- [electron-cfg](https://github.com/megahertz/electron-cfg) -
Settings for your Electron application.

6
mc_test/node_modules/electron-log/main.d.ts generated vendored Executable file
View File

@ -0,0 +1,6 @@
import { MainLogger } from './src';
declare const Logger: MainLogger & {
default: MainLogger;
};
export = Logger;

5
mc_test/node_modules/electron-log/main.js generated vendored Executable file
View File

@ -0,0 +1,5 @@
'use strict';
const main = require('./src/main');
module.exports = main;

6
mc_test/node_modules/electron-log/node.d.ts generated vendored Executable file
View File

@ -0,0 +1,6 @@
import { NodeLogger } from './src';
declare const Logger: NodeLogger & {
default: NodeLogger;
};
export = Logger;

5
mc_test/node_modules/electron-log/node.js generated vendored Executable file
View File

@ -0,0 +1,5 @@
'use strict';
const node = require('./src/node');
module.exports = node;

64
mc_test/node_modules/electron-log/package.json generated vendored Executable file
View File

@ -0,0 +1,64 @@
{
"name": "electron-log",
"version": "5.4.1",
"description": "Just a simple logging module for your Electron application",
"main": "src/index.js",
"browser": "src/renderer/index.js",
"engines": {
"node": ">= 14"
},
"scripts": {
"lint": "eslint '**/*.{js,cjs}' --ignore-pattern '**/dist/*.js' && tsc --noEmit",
"test": "humile 'src/**/*spec.js'",
"test:full": "npm run test && npm run lint && npm run test:e2e",
"test:e2e": "humile 'e2e/**/*.spec.{js,cjs}' -R list",
"postversion": "git push && git push --tags",
"prepack": "npm run test:full",
"preversion": "npm run test:full"
},
"typings": "src/index.d.ts",
"repository": "megahertz/electron-log",
"files": [
"src/*",
"!**/__specs__",
"!**/.*",
"main.js",
"main.d.ts",
"node.js",
"node.d.ts",
"preload.js",
"renderer.js",
"renderer.d.ts"
],
"keywords": [
"electron",
"atom",
"log",
"logger",
"logging",
"windows",
"mac",
"osx",
"linux",
"desktop"
],
"author": "Alexey Prokhorov",
"license": "MIT",
"bugs": "https://github.com/megahertz/electron-log/issues",
"homepage": "https://github.com/megahertz/electron-log#readme",
"devDependencies": {
"@types/node": "^20.10.6",
"electron": "*",
"eslint": "^8.56.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.29.1",
"humile": "^0.5.3",
"nw": "^0.83.0",
"typescript": "^5.3.3",
"vite": "^4.5.9",
"vite-plugin-electron": "^0.15.5",
"vite-plugin-electron-renderer": "^0.14.5",
"webpack": "^5.89.0",
"webpack-cli": "^5.1.4"
}
}

5
mc_test/node_modules/electron-log/preload.js generated vendored Executable file
View File

@ -0,0 +1,5 @@
'use strict';
const preload = require('./src/renderer/electron-log-preload');
module.exports = preload;

6
mc_test/node_modules/electron-log/renderer.d.ts generated vendored Executable file
View File

@ -0,0 +1,6 @@
import { RendererLogger } from './src';
declare const Logger: RendererLogger & {
default: RendererLogger;
};
export = Logger;

5
mc_test/node_modules/electron-log/renderer.js generated vendored Executable file
View File

@ -0,0 +1,5 @@
'use strict';
const renderer = require('./src/renderer');
module.exports = renderer;

34
mc_test/node_modules/electron-log/src/core/Buffering.js generated vendored Executable file
View File

@ -0,0 +1,34 @@
'use strict';
class Buffering {
constructor({ processMessage }) {
this.processMessage = processMessage;
this.buffer = [];
this.enabled = false;
this.begin = this.begin.bind(this);
this.commit = this.commit.bind(this);
this.reject = this.reject.bind(this);
}
addMessage(message) {
this.buffer.push(message);
}
begin() {
this.enabled = [];
}
commit() {
this.enabled = false;
this.buffer.forEach((item) => this.processMessage(item));
this.buffer = [];
}
reject() {
this.enabled = false;
this.buffer = [];
}
}
module.exports = Buffering;

214
mc_test/node_modules/electron-log/src/core/Logger.js generated vendored Executable file
View File

@ -0,0 +1,214 @@
'use strict';
const scopeFactory = require('./scope');
const Buffering = require('./Buffering');
/**
* @property {Function} error
* @property {Function} warn
* @property {Function} info
* @property {Function} verbose
* @property {Function} debug
* @property {Function} silly
*/
class Logger {
static instances = {};
dependencies = {};
errorHandler = null;
eventLogger = null;
functions = {};
hooks = [];
isDev = false;
levels = null;
logId = null;
scope = null;
transports = {};
variables = {};
constructor({
allowUnknownLevel = false,
dependencies = {},
errorHandler,
eventLogger,
initializeFn,
isDev = false,
levels = ['error', 'warn', 'info', 'verbose', 'debug', 'silly'],
logId,
transportFactories = {},
variables,
} = {}) {
this.addLevel = this.addLevel.bind(this);
this.create = this.create.bind(this);
this.initialize = this.initialize.bind(this);
this.logData = this.logData.bind(this);
this.processMessage = this.processMessage.bind(this);
this.allowUnknownLevel = allowUnknownLevel;
this.buffering = new Buffering(this);
this.dependencies = dependencies;
this.initializeFn = initializeFn;
this.isDev = isDev;
this.levels = levels;
this.logId = logId;
this.scope = scopeFactory(this);
this.transportFactories = transportFactories;
this.variables = variables || {};
for (const name of this.levels) {
this.addLevel(name, false);
}
this.log = this.info;
this.functions.log = this.log;
this.errorHandler = errorHandler;
errorHandler?.setOptions({ ...dependencies, logFn: this.error });
this.eventLogger = eventLogger;
eventLogger?.setOptions({ ...dependencies, logger: this });
for (const [name, factory] of Object.entries(transportFactories)) {
this.transports[name] = factory(this, dependencies);
}
Logger.instances[logId] = this;
}
static getInstance({ logId }) {
return this.instances[logId] || this.instances.default;
}
addLevel(level, index = this.levels.length) {
if (index !== false) {
this.levels.splice(index, 0, level);
}
this[level] = (...args) => this.logData(args, { level });
this.functions[level] = this[level];
}
catchErrors(options) {
this.processMessage(
{
data: ['log.catchErrors is deprecated. Use log.errorHandler instead'],
level: 'warn',
},
{ transports: ['console'] },
);
return this.errorHandler.startCatching(options);
}
create(options) {
if (typeof options === 'string') {
options = { logId: options };
}
return new Logger({
dependencies: this.dependencies,
errorHandler: this.errorHandler,
initializeFn: this.initializeFn,
isDev: this.isDev,
transportFactories: this.transportFactories,
variables: { ...this.variables },
...options,
});
}
compareLevels(passLevel, checkLevel, levels = this.levels) {
const pass = levels.indexOf(passLevel);
const check = levels.indexOf(checkLevel);
if (check === -1 || pass === -1) {
return true;
}
return check <= pass;
}
initialize(options = {}) {
this.initializeFn({ logger: this, ...this.dependencies, ...options });
}
logData(data, options = {}) {
if (this.buffering.enabled) {
this.buffering.addMessage({ data, date: new Date(), ...options });
} else {
this.processMessage({ data, ...options });
}
}
processMessage(message, { transports = this.transports } = {}) {
if (message.cmd === 'errorHandler') {
this.errorHandler.handle(message.error, {
errorName: message.errorName,
processType: 'renderer',
showDialog: Boolean(message.showDialog),
});
return;
}
let level = message.level;
if (!this.allowUnknownLevel) {
level = this.levels.includes(message.level) ? message.level : 'info';
}
const normalizedMessage = {
date: new Date(),
logId: this.logId,
...message,
level,
variables: {
...this.variables,
...message.variables,
},
};
for (const [transName, transFn] of this.transportEntries(transports)) {
if (typeof transFn !== 'function' || transFn.level === false) {
continue;
}
if (!this.compareLevels(transFn.level, message.level)) {
continue;
}
try {
// eslint-disable-next-line arrow-body-style
const transformedMsg = this.hooks.reduce((msg, hook) => {
return msg ? hook(msg, transFn, transName) : msg;
}, normalizedMessage);
if (transformedMsg) {
transFn({ ...transformedMsg, data: [...transformedMsg.data] });
}
} catch (e) {
this.processInternalErrorFn(e);
}
}
}
processInternalErrorFn(_e) {
// Do nothing by default
}
transportEntries(transports = this.transports) {
const transportArray = Array.isArray(transports)
? transports
: Object.entries(transports);
return transportArray
.map((item) => {
switch (typeof item) {
case 'string':
return this.transports[item] ? [item, this.transports[item]] : null;
case 'function':
return [item.name, item];
default:
return Array.isArray(item) ? item : null;
}
})
.filter(Boolean);
}
}
module.exports = Logger;

31
mc_test/node_modules/electron-log/src/core/scope.js generated vendored Executable file
View File

@ -0,0 +1,31 @@
'use strict';
module.exports = scopeFactory;
function scopeFactory(logger) {
return Object.defineProperties(scope, {
defaultLabel: { value: '', writable: true },
labelPadding: { value: true, writable: true },
maxLabelLength: { value: 0, writable: true },
labelLength: {
get() {
switch (typeof scope.labelPadding) {
case 'boolean': return scope.labelPadding ? scope.maxLabelLength : 0;
case 'number': return scope.labelPadding;
default: return 0;
}
},
},
});
function scope(label) {
scope.maxLabelLength = Math.max(scope.maxLabelLength, label.length);
const newScope = {};
for (const level of logger.levels) {
newScope[level] = (...d) => logger.logData(d, { level, scope: label });
}
newScope.log = newScope.info;
return newScope;
}
}

View File

@ -0,0 +1,157 @@
'use strict';
const { transform } = require('./transform');
module.exports = {
concatFirstStringElements,
formatScope,
formatText,
formatVariables,
timeZoneFromOffset,
format({ message, logger, transport, data = message?.data }) {
switch (typeof transport.format) {
case 'string': {
return transform({
message,
logger,
transforms: [formatVariables, formatScope, formatText],
transport,
initialData: [transport.format, ...data],
});
}
case 'function': {
return transport.format({
data,
level: message?.level || 'info',
logger,
message,
transport,
});
}
default: {
return data;
}
}
},
};
/**
* The first argument of console.log may contain a template. In the library
* the first element is a string related to transports.console.format. So
* this function concatenates first two elements to make templates like %d
* work
* @param {*[]} data
* @return {*[]}
*/
function concatFirstStringElements({ data }) {
if (typeof data[0] !== 'string' || typeof data[1] !== 'string') {
return data;
}
if (data[0].match(/%[1cdfiOos]/)) {
return data;
}
return [`${data[0]} ${data[1]}`, ...data.slice(2)];
}
function timeZoneFromOffset(minutesOffset) {
const minutesPositive = Math.abs(minutesOffset);
const sign = minutesOffset > 0 ? '-' : '+';
const hours = Math.floor(minutesPositive / 60).toString().padStart(2, '0');
const minutes = (minutesPositive % 60).toString().padStart(2, '0');
return `${sign}${hours}:${minutes}`;
}
function formatScope({ data, logger, message }) {
const { defaultLabel, labelLength } = logger?.scope || {};
const template = data[0];
let label = message.scope;
if (!label) {
label = defaultLabel;
}
let scopeText;
if (label === '') {
scopeText = labelLength > 0 ? ''.padEnd(labelLength + 3) : '';
} else if (typeof label === 'string') {
scopeText = ` (${label})`.padEnd(labelLength + 3);
} else {
scopeText = '';
}
data[0] = template.replace('{scope}', scopeText);
return data;
}
function formatVariables({ data, message }) {
let template = data[0];
if (typeof template !== 'string') {
return data;
}
// Add additional space to the end of {level}] template to align messages
template = template.replace('{level}]', `${message.level}]`.padEnd(6, ' '));
const date = message.date || new Date();
data[0] = template
.replace(/\{(\w+)}/g, (substring, name) => {
switch (name) {
case 'level': return message.level || 'info';
case 'logId': return message.logId;
case 'y': return date.getFullYear().toString(10);
case 'm': return (date.getMonth() + 1).toString(10).padStart(2, '0');
case 'd': return date.getDate().toString(10).padStart(2, '0');
case 'h': return date.getHours().toString(10).padStart(2, '0');
case 'i': return date.getMinutes().toString(10).padStart(2, '0');
case 's': return date.getSeconds().toString(10).padStart(2, '0');
case 'ms': return date.getMilliseconds().toString(10).padStart(3, '0');
case 'z': return timeZoneFromOffset(date.getTimezoneOffset());
case 'iso': return date.toISOString();
default: {
return message.variables?.[name] || substring;
}
}
})
.trim();
return data;
}
function formatText({ data }) {
const template = data[0];
if (typeof template !== 'string') {
return data;
}
const textTplPosition = template.lastIndexOf('{text}');
if (textTplPosition === template.length - 6) {
data[0] = template.replace(/\s?{text}/, '');
if (data[0] === '') {
data.shift();
}
return data;
}
const templatePieces = template.split('{text}');
let result = [];
if (templatePieces[0] !== '') {
result.push(templatePieces[0]);
}
result = result.concat(data.slice(1));
if (templatePieces[1] !== '') {
result.push(templatePieces[1]);
}
return result;
}

View File

@ -0,0 +1,73 @@
'use strict';
module.exports = {
transformStyles,
applyAnsiStyles({ data }) {
return transformStyles(data, styleToAnsi, resetAnsiStyle);
},
removeStyles({ data }) {
return transformStyles(data, () => '');
},
};
const ANSI_COLORS = {
unset: '\x1b[0m',
black: '\x1b[30m',
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m',
white: '\x1b[37m',
};
function styleToAnsi(style) {
const color = style.replace(/color:\s*(\w+).*/, '$1').toLowerCase();
return ANSI_COLORS[color] || '';
}
function resetAnsiStyle(string) {
return string + ANSI_COLORS.unset;
}
function transformStyles(data, onStyleFound, onStyleApplied) {
const foundStyles = {};
return data.reduce((result, item, index, array) => {
if (foundStyles[index]) {
return result;
}
if (typeof item === 'string') {
let valueIndex = index;
let styleApplied = false;
item = item.replace(/%[1cdfiOos]/g, (match) => {
valueIndex += 1;
if (match !== '%c') {
return match;
}
const style = array[valueIndex];
if (typeof style === 'string') {
foundStyles[valueIndex] = true;
styleApplied = true;
return onStyleFound(style, item);
}
return match;
});
if (styleApplied && onStyleApplied) {
item = onStyleApplied(item);
}
}
result.push(item);
return result;
}, []);
}

View File

@ -0,0 +1,20 @@
'use strict';
module.exports = { transform };
function transform({
logger,
message,
transport,
initialData = message?.data || [],
transforms = transport?.transforms,
}) {
return transforms.reduce((data, trans) => {
if (typeof trans === 'function') {
return trans({ data, logger, message, transport });
}
return data;
}, initialData);
}

685
mc_test/node_modules/electron-log/src/index.d.ts generated vendored Executable file
View File

@ -0,0 +1,685 @@
import { ClientRequest, RequestOptions } from 'http';
import { InspectOptions } from 'util';
declare namespace Logger {
type LogLevel = 'error' | 'warn' | 'info' | 'verbose' | 'debug' |
'silly';
type LevelOption = LogLevel | false;
interface FormatParams {
data: any[];
level: LogLevel;
logger: Logger;
message: LogMessage;
transport: Transport;
}
type Format = string | ((params: FormatParams) => any[]);
type FOpenFlags = 'r' | 'r+' | 'rs+' | 'w' | 'wx' | 'w+' | 'wx+' |
'a' | 'ax' | 'a+' | 'ax+';
type Hook = (
message: LogMessage,
transport?: Transport,
transportName?: string,
) => LogMessage | false;
interface Variables {
processType: string;
[name: string]: any;
}
type TransformFn = (options: {
data: any[],
message: LogMessage,
transport: Transport,
logger: Logger
}) => any;
interface LogMessage {
/**
* Any arguments passed to a log function
*/
data: any[];
/**
* When the log entry was created
*/
date: Date;
/**
* From error to silly
*/
level: LogLevel;
/**
* Id of Logger instance
*/
logId?: string;
/**
* Message scope label
*/
scope?: string;
/**
* Variables used by formatter
*/
variables?: Variables;
}
interface Transport {
(message: LogMessage): void;
/**
* Messages with level lower than will be dropped
*/
level: LevelOption;
transforms: TransformFn[];
}
interface ConsoleTransport extends Transport {
/**
* String template of function for message serialization
*/
format: Format | string;
/**
* Use styles even if TTY isn't attached
*/
useStyles: boolean;
/**
* Override message printing
*/
writeFn(options: { message: LogMessage }): void;
}
interface PathVariables {
/**
* Per-user application data directory, which by default points to:
* %APPDATA% on Windows
* $XDG_CONFIG_HOME or ~/.config on Linux
* ~/Library/Application Support on macOS
*/
readonly appData: string;
/**
* Application name from productName or name of package.json
*/
readonly appName: string;
/**
* Application version from package.json
*/
readonly appVersion: string;
/**
* app.getPath('logs'). May be unavailable in old versions
*/
readonly electronDefaultDir?: string;
/**
* Name of the log file without path
*/
readonly fileName?: string;
/**
* User's home directory
*/
readonly home: string;
/**
* userData + /logs/ + fileName on Linux and Windows
* ~/Library/Logs/ + appName + / + fileName on macOS
*/
readonly libraryDefaultDir: string;
/**
* Same as libraryDefaultDir, but contains '{appName}' template instead
* of the real application name
*/
readonly libraryTemplate: string;
/**
* OS temporary path
*/
readonly tempDir: string;
/**
* The directory for storing your app's configuration files, which by
* default it is the appData directory appended with your app's name.
*/
readonly userData: string;
}
interface WriteOptions {
/**
* Default 'a'
*/
flag?: FOpenFlags;
/**
* Default 0666
*/
mode?: number;
/**
* Default 'utf8'
*/
encoding?: string;
}
interface LogFile {
/**
* Full log file path
*/
readonly path: string;
/**
* How many bytes were written since transport initialization
*/
readonly bytesWritten: number;
/**
* Current file size
*/
readonly size: number;
/**
* Clear the log file
*/
clear(): boolean;
/**
* Emitted when there was some error while saving log file
*/
on(event: 'error', listener: (error: Error, file: this) => void): this;
}
interface FileTransport extends Transport {
/**
* Deprecated alias of archiveLogFn
* @deprecated
*/
archiveLog: (oldLogFile: LogFile) => void;
/**
* Function which is called on log rotation. You can override it if you need
* custom log rotation behavior. This function should remove old file
* synchronously
*/
archiveLogFn: (oldLogFile: LogFile) => void;
/**
* How deep to serialize complex objects
* Deprecated in favor of inspectOptions
* @deprecated
*/
depth: number;
/**
* Filename without path, main.log (or renderer.log) by default
*/
fileName: string;
/**
* String template of function for message serialization
*/
format: Format | string;
/**
* Return the current log file instance
* You only need to provide message argument if you define log path inside
* resolvePath callback depending on a message.
*/
getFile(message?: Partial<LogMessage>): LogFile;
/**
* Serialization options
* @link https://nodejs.org/api/util.html#util_util_inspect_object_options
*/
inspectOptions: InspectOptions;
/**
* Maximum size of log file in bytes, 1048576 (1mb) by default. When a log
* file exceeds this limit, it will be moved to log.old.log file and the
* current file will be cleared. You can set it to 0 to disable rotation
*/
maxSize: number;
/**
* Reads content of all log files
*/
readAllLogs(
options?: { fileFilter?: (logPath: string) => boolean },
): Array<{ path: string, lines: string[] }>;
/**
* Alias for resolvePathFn
* @deprecated
*/
resolvePath: (variables: PathVariables, message?: LogMessage) => string;
/**
* Allow to change log file path dynamically
*/
resolvePathFn: (variables: PathVariables, message?: LogMessage) => string;
/**
* Override appName used for resolving log path
* @param appName
*/
setAppName(appName: string): void;
/**
* Whether to write a log file synchronously. Default to true
*/
sync: boolean;
/**
* Options used when writing a file
*/
writeOptions?: WriteOptions;
}
interface RemoteTransport extends Transport {
/**
* Client information which will be sent in each request together with
* a message body
*/
client?: object;
/**
* How deep to serialize complex objects
*/
depth?: number;
/**
* Additional options for the HTTP request
*/
requestOptions?: RequestOptions;
/**
* Callback which is called on request error
*/
processErrorFn: (error: Error) => void;
/**
* Callback which transforms request body to string
*/
makeBodyFn: (
options: { logger: Logger, message: LogMessage, transport: Transport },
) => any;
/**
* Callback which allows to customize request sending
*/
sendRequestFn: (
options: { serverUrl: string, requestOptions: RequestOptions, body: any }
) => ClientRequest;
/**
* Server URL
*/
url: string;
}
interface MainTransports {
/**
* Writes logs to console
*/
console: ConsoleTransport;
/**
* Writes logs to a file
*/
file: FileTransport;
/**
* Display main process logs in the renderer dev tools console
*/
ipc: Transport;
/**
* Sends a JSON POST request with LogMessage in the body to the specified url
*/
remote: RemoteTransport;
[key: string]: Transport | null;
}
interface RendererTransports {
/**
* Writes logs to console
*/
console: ConsoleTransport;
/**
* Communicates with a main process logger
*/
ipc: Transport;
[key: string]: Transport | null;
}
interface Buffering {
/**
* Buffered log messages
*/
buffer: LogMessage[];
enabled: boolean;
/**
* Start buffering log messages
*/
begin(): void;
/**
* Stop buffering and process all buffered logs
*/
commit(): void;
/**
* Stop buffering and discard all buffered logs
*/
reject(): void;
}
interface Scope {
(label: string): LogFunctions;
/**
* Label for log message without scope. If set to false and scope isn't
* set, no padding is used
*/
defaultLabel: string | false;
/**
* Pad scope label using spaces
* false: disabled
* true: automatically
* number: set exact maximum label length. Helpful when a scope can
* be created after some log messages were sent
*/
labelPadding: boolean | number;
}
interface ReportData {
body: string;
title: string;
assignee: string;
labels: string;
milestone: string;
projects: string;
template: string;
}
interface LogFunctions {
/**
* Log an error message
*/
error(...params: any[]): void;
/**
* Log a warning message
*/
warn(...params: any[]): void;
/**
* Log an informational message
*/
info(...params: any[]): void;
/**
* Log a verbose message
*/
verbose(...params: any[]): void;
/**
* Log a debug message
*/
debug(...params: any[]): void;
/**
* Log a silly message
*/
silly(...params: any[]): void;
/**
* Shortcut to info
*/
log(...params: any[]): void;
}
interface ErrorHandlerOptions {
/**
* Default true for the main process. Set it to false to prevent showing a
* default electron error dialog
*/
showDialog?: boolean;
/**
* Attach a custom error handler. If the handler returns false, this error
* will not be processed
*/
onError?(options: {
createIssue: (url: string, data: ReportData | any) => void,
error: Error,
errorName: 'Unhandled' | 'Unhandled rejection',
processType: 'browser' | 'renderer',
versions: { app: string; electron: string; os: string },
}): void;
}
interface MainErrorHandlerOptions extends ErrorHandlerOptions {
/**
* Attach a custom error handler. If the handler returns false, this error
* will not be processed
*/
onError?(options: {
createIssue: (url: string, data: ReportData | any) => void,
error: Error,
errorName: 'Unhandled' | 'Unhandled rejection',
processType: 'browser' | 'renderer',
versions: { app: string; electron: string; os: string },
}): void;
}
interface RendererErrorHandlerOptions extends ErrorHandlerOptions {
/**
* Attach a custom error handler. If the handler returns false, this error
* will not be processed
*/
onError?(options: {
error: Error,
errorName: 'Unhandled' | 'Unhandled rejection',
processType: 'browser' | 'renderer',
}): void;
/**
* By default, error and unhandledrejection handlers call preventDefault to
* prevent error duplicating in console. Set false to disable it
*/
preventDefault?: boolean;
}
interface ErrorHandler<T = ErrorHandlerOptions> {
/**
* Process an error by the ErrorHandler
*/
handle(error: Error, options?: T): void;
/**
* Change some options
*/
setOptions(options: T): void;
/**
* Start catching unhandled errors and rejections
*/
startCatching(options?: T): void;
/**
* Stop catching unhandled errors and rejections
*/
stopCatching(): void;
}
type EventSource = 'app' | 'webContents';
interface EventFormatterInput {
args: unknown[];
event: object;
eventName: string;
eventSource: string;
}
interface EventLoggerOptions {
/**
* String template or function which prepares event data for logging
*/
format?: string | ((input: EventFormatterInput) => unknown[]);
/**
* Formatter callbacks for a specific event
*/
formatters?: Record<
EventSource,
Record<string, (input: EventFormatterInput) => object | unknown[]>
>;
/**
* Allow switching specific events on/off easily
*/
events?: Record<EventSource, Record<string, boolean>>;
/**
* Which log level is used for logging. Default warn
*/
level?: LogLevel;
/**
* Which log scope is used for logging. Default '' (none)
*/
scope?: string;
}
interface EventLogger extends Required<EventLoggerOptions> {
setOptions(options: EventLoggerOptions): void;
startLogging(options?: EventLoggerOptions): void;
stopLogging(): void;
}
interface Logger extends LogFunctions {
/**
* Buffering helper
*/
buffering: Buffering;
/**
* Error handling helper
*/
errorHandler: ErrorHandler;
/**
* Object contained only log functions
*/
functions: LogFunctions;
/**
* Array with all attached hooks
*/
hooks: Hook[];
/**
* Array with all available levels
*/
levels: string[];
/**
* ID of the current logger instance
*/
logId: string;
/**
* Create a new scope
*/
scope: Scope;
/**
* Transport instances
*/
transports: { [key: string]: Transport | null; };
/**
* Variables used by formatters
*/
variables: Variables;
/**
* Add a custom log level
*/
addLevel(level: string, index?: number): void;
/**
* Catch and log unhandled errors/rejected promises
* @deprecated
*/
catchErrors(options?: ErrorHandlerOptions): ErrorHandler;
/**
* Create a new electron-log instance
*/
create(options: { logId: string }): this;
/**
* Low level method which logs the message using specified transports
*/
processMessage(
message: LogMessage,
options?: { transports?: Transport[] | string[] },
): void;
}
interface NodeLogger extends Logger {
errorHandler: ErrorHandler<MainErrorHandlerOptions>;
eventLogger: EventLogger;
transports: MainTransports;
}
interface MainLogger extends NodeLogger {
initialize(
options?: {
getSessions?: () => object[];
includeFutureSessions?: boolean;
preload?: string | boolean;
spyRendererConsole?: boolean;
},
): void;
}
interface RendererLogger extends Logger {
errorHandler: ErrorHandler<RendererErrorHandlerOptions>;
transports: RendererTransports;
}
}
// Merge namespace with interface
declare const Logger: Logger.MainLogger & {
default: Logger.MainLogger;
};
export = Logger;
declare global {
const __electronLog: Logger.LogFunctions;
interface Window {
__electronLog: Logger.LogFunctions;
}
}

18
mc_test/node_modules/electron-log/src/index.js generated vendored Executable file
View File

@ -0,0 +1,18 @@
'use strict';
/* eslint-disable global-require */
const isRenderer = typeof process === 'undefined'
|| (process.type === 'renderer' || process.type === 'worker');
const isMain = typeof process === 'object' && process.type === 'browser';
if (isRenderer) {
// Makes sense when contextIsolation/sandbox disabled
require('./renderer/electron-log-preload');
module.exports = require('./renderer');
} else if (isMain) {
module.exports = require('./main');
} else {
module.exports = require('./node');
}

View File

@ -0,0 +1,200 @@
'use strict';
const path = require('path');
const NodeExternalApi = require('../node/NodeExternalApi');
class ElectronExternalApi extends NodeExternalApi {
/**
* @type {typeof Electron}
*/
electron = undefined;
/**
* @param {object} options
* @param {typeof Electron} [options.electron]
*/
constructor({ electron } = {}) {
super();
this.electron = electron;
}
getAppName() {
let appName;
try {
appName = this.appName
|| this.electron.app?.name
|| this.electron.app?.getName();
} catch {
// fallback to default value below
}
return appName || super.getAppName();
}
getAppUserDataPath(appName) {
return this.getPath('userData') || super.getAppUserDataPath(appName);
}
getAppVersion() {
let appVersion;
try {
appVersion = this.electron.app?.getVersion();
} catch {
// fallback to default value below
}
return appVersion || super.getAppVersion();
}
getElectronLogPath() {
return this.getPath('logs') || super.getElectronLogPath();
}
/**
* @private
* @param {any} name
* @returns {string|undefined}
*/
getPath(name) {
try {
return this.electron.app?.getPath(name);
} catch {
return undefined;
}
}
getVersions() {
return {
app: `${this.getAppName()} ${this.getAppVersion()}`,
electron: `Electron ${process.versions.electron}`,
os: this.getOsVersion(),
};
}
getSystemPathAppData() {
return this.getPath('appData') || super.getSystemPathAppData();
}
isDev() {
if (this.electron.app?.isPackaged !== undefined) {
return !this.electron.app.isPackaged;
}
if (typeof process.execPath === 'string') {
const execFileName = path.basename(process.execPath).toLowerCase();
return execFileName.startsWith('electron');
}
return super.isDev();
}
onAppEvent(eventName, handler) {
this.electron.app?.on(eventName, handler);
return () => {
this.electron.app?.off(eventName, handler);
};
}
onAppReady(handler) {
if (this.electron.app?.isReady()) {
handler();
} else if (this.electron.app?.once) {
this.electron.app?.once('ready', handler);
} else {
handler();
}
}
onEveryWebContentsEvent(eventName, handler) {
this.electron.webContents?.getAllWebContents()?.forEach((webContents) => {
webContents.on(eventName, handler);
});
this.electron.app?.on('web-contents-created', onWebContentsCreated);
return () => {
this.electron.webContents?.getAllWebContents().forEach((webContents) => {
webContents.off(eventName, handler);
});
this.electron.app?.off('web-contents-created', onWebContentsCreated);
};
function onWebContentsCreated(_, webContents) {
webContents.on(eventName, handler);
}
}
/**
* Listen to async messages sent from opposite process
* @param {string} channel
* @param {function} listener
*/
onIpc(channel, listener) {
this.electron.ipcMain?.on(channel, listener);
}
onIpcInvoke(channel, listener) {
this.electron.ipcMain?.handle?.(channel, listener);
}
/**
* @param {string} url
* @param {Function} [logFunction]
*/
openUrl(url, logFunction = console.error) { // eslint-disable-line no-console
this.electron.shell?.openExternal(url).catch(logFunction);
}
setPreloadFileForSessions({
filePath,
includeFutureSession = true,
getSessions = () => [this.electron.session?.defaultSession],
}) {
for (const session of getSessions().filter(Boolean)) {
setPreload(session);
}
if (includeFutureSession) {
this.onAppEvent('session-created', (session) => {
setPreload(session);
});
}
/**
* @param {Session} session
*/
function setPreload(session) {
if (typeof session.registerPreloadScript === 'function') {
session.registerPreloadScript({
filePath,
id: 'electron-log-preload',
type: 'frame',
});
} else {
session.setPreloads([...session.getPreloads(), filePath]);
}
}
}
/**
* Sent a message to opposite process
* @param {string} channel
* @param {any} message
*/
sendIpc(channel, message) {
this.electron.BrowserWindow?.getAllWindows()?.forEach((wnd) => {
if (
wnd.webContents?.isDestroyed() === false
&& wnd.webContents?.isCrashed() === false
) {
wnd.webContents.send(channel, message);
}
});
}
showErrorBox(title, message) {
this.electron.dialog?.showErrorBox(title, message);
}
}
module.exports = ElectronExternalApi;

47
mc_test/node_modules/electron-log/src/main/index.js generated vendored Executable file
View File

@ -0,0 +1,47 @@
'use strict';
const electron = require('electron');
const ElectronExternalApi = require('./ElectronExternalApi');
const { initialize } = require('./initialize');
const createDefaultLogger = require('../node/createDefaultLogger');
const externalApi = new ElectronExternalApi({ electron });
const defaultLogger = createDefaultLogger({
dependencies: { externalApi },
initializeFn: initialize,
});
module.exports = defaultLogger;
externalApi.onIpc('__ELECTRON_LOG__', (_, message) => {
if (message.scope) {
defaultLogger.Logger.getInstance(message).scope(message.scope);
}
const date = new Date(message.date);
processMessage({
...message,
date: date.getTime() ? date : new Date(),
});
});
externalApi.onIpcInvoke('__ELECTRON_LOG__', (_, { cmd = '', logId }) => {
switch (cmd) {
case 'getOptions': {
const logger = defaultLogger.Logger.getInstance({ logId });
return {
levels: logger.levels,
logId,
};
}
default: {
processMessage({ data: [`Unknown cmd '${cmd}'`], level: 'error' });
return {};
}
}
});
function processMessage(message) {
defaultLogger.Logger.getInstance(message)?.processMessage(message);
}

91
mc_test/node_modules/electron-log/src/main/initialize.js generated vendored Executable file
View File

@ -0,0 +1,91 @@
'use strict';
const fs = require('fs');
const os = require('os');
const path = require('path');
const preloadInitializeFn = require('../renderer/electron-log-preload');
module.exports = {
initialize({
externalApi,
getSessions,
includeFutureSession,
logger,
preload = true,
spyRendererConsole = false,
}) {
externalApi.onAppReady(() => {
try {
if (preload) {
initializePreload({
externalApi,
getSessions,
includeFutureSession,
preloadOption: preload,
});
}
if (spyRendererConsole) {
initializeSpyRendererConsole({ externalApi, logger });
}
} catch (err) {
logger.warn(err);
}
});
},
};
function initializePreload({
externalApi,
getSessions,
includeFutureSession,
preloadOption,
}) {
let preloadPath = typeof preloadOption === 'string'
? preloadOption
: undefined;
try {
preloadPath = path.resolve(
__dirname,
'../renderer/electron-log-preload.js',
);
} catch {
// Ignore, the file is bundled to ESM
}
if (!preloadPath || !fs.existsSync(preloadPath)) {
preloadPath = path.join(
externalApi.getAppUserDataPath() || os.tmpdir(),
'electron-log-preload.js',
);
const preloadCode = `
try {
(${preloadInitializeFn.toString()})(require('electron'));
} catch(e) {
console.error(e);
}
`;
fs.writeFileSync(preloadPath, preloadCode, 'utf8');
}
externalApi.setPreloadFileForSessions({
filePath: preloadPath,
includeFutureSession,
getSessions,
});
}
function initializeSpyRendererConsole({ externalApi, logger }) {
const levels = ['debug', 'info', 'warn', 'error'];
externalApi.onEveryWebContentsEvent(
'console-message',
(event, level, message) => {
logger.processMessage({
data: [message],
level: levels[level],
variables: { processType: 'renderer' },
});
},
);
}

134
mc_test/node_modules/electron-log/src/node/ErrorHandler.js generated vendored Executable file
View File

@ -0,0 +1,134 @@
'use strict';
class ErrorHandler {
externalApi = undefined;
isActive = false;
logFn = undefined;
onError = undefined;
showDialog = true;
constructor({
externalApi,
logFn = undefined,
onError = undefined,
showDialog = undefined,
} = {}) {
this.createIssue = this.createIssue.bind(this);
this.handleError = this.handleError.bind(this);
this.handleRejection = this.handleRejection.bind(this);
this.setOptions({ externalApi, logFn, onError, showDialog });
this.startCatching = this.startCatching.bind(this);
this.stopCatching = this.stopCatching.bind(this);
}
handle(error, {
logFn = this.logFn,
onError = this.onError,
processType = 'browser',
showDialog = this.showDialog,
errorName = '',
} = {}) {
error = normalizeError(error);
try {
if (typeof onError === 'function') {
const versions = this.externalApi?.getVersions() || {};
const createIssue = this.createIssue;
const result = onError({
createIssue,
error,
errorName,
processType,
versions,
});
if (result === false) {
return;
}
}
errorName ? logFn(errorName, error) : logFn(error);
if (showDialog && !errorName.includes('rejection') && this.externalApi) {
this.externalApi.showErrorBox(
`A JavaScript error occurred in the ${processType} process`,
error.stack,
);
}
} catch {
console.error(error); // eslint-disable-line no-console
}
}
setOptions({ externalApi, logFn, onError, showDialog }) {
if (typeof externalApi === 'object') {
this.externalApi = externalApi;
}
if (typeof logFn === 'function') {
this.logFn = logFn;
}
if (typeof onError === 'function') {
this.onError = onError;
}
if (typeof showDialog === 'boolean') {
this.showDialog = showDialog;
}
}
startCatching({ onError, showDialog } = {}) {
if (this.isActive) {
return;
}
this.isActive = true;
this.setOptions({ onError, showDialog });
process.on('uncaughtException', this.handleError);
process.on('unhandledRejection', this.handleRejection);
}
stopCatching() {
this.isActive = false;
process.removeListener('uncaughtException', this.handleError);
process.removeListener('unhandledRejection', this.handleRejection);
}
createIssue(pageUrl, queryParams) {
this.externalApi?.openUrl(
`${pageUrl}?${new URLSearchParams(queryParams).toString()}`,
);
}
handleError(error) {
this.handle(error, { errorName: 'Unhandled' });
}
handleRejection(reason) {
const error = reason instanceof Error
? reason
: new Error(JSON.stringify(reason));
this.handle(error, { errorName: 'Unhandled rejection' });
}
}
function normalizeError(e) {
if (e instanceof Error) {
return e;
}
if (e && typeof e === 'object') {
if (e.message) {
return Object.assign(new Error(e.message), e);
}
try {
return new Error(JSON.stringify(e));
} catch (serErr) {
return new Error(`Couldn't normalize error ${String(e)}: ${serErr}`);
}
}
return new Error(`Can't normalize error ${String(e)}`);
}
module.exports = ErrorHandler;

247
mc_test/node_modules/electron-log/src/node/EventLogger.js generated vendored Executable file
View File

@ -0,0 +1,247 @@
'use strict';
class EventLogger {
disposers = [];
format = '{eventSource}#{eventName}:';
formatters = {
app: {
'certificate-error': ({ args }) => {
return this.arrayToObject(args.slice(1, 4), [
'url',
'error',
'certificate',
]);
},
'child-process-gone': ({ args }) => {
return args.length === 1 ? args[0] : args;
},
'render-process-gone': ({ args: [webContents, details] }) => {
return details && typeof details === 'object'
? { ...details, ...this.getWebContentsDetails(webContents) }
: [];
},
},
webContents: {
'console-message': ({ args: [level, message, line, sourceId] }) => {
// 0: debug, 1: info, 2: warning, 3: error
if (level < 3) {
return undefined;
}
return { message, source: `${sourceId}:${line}` };
},
'did-fail-load': ({ args }) => {
return this.arrayToObject(args, [
'errorCode',
'errorDescription',
'validatedURL',
'isMainFrame',
'frameProcessId',
'frameRoutingId',
]);
},
'did-fail-provisional-load': ({ args }) => {
return this.arrayToObject(args, [
'errorCode',
'errorDescription',
'validatedURL',
'isMainFrame',
'frameProcessId',
'frameRoutingId',
]);
},
'plugin-crashed': ({ args }) => {
return this.arrayToObject(args, ['name', 'version']);
},
'preload-error': ({ args }) => {
return this.arrayToObject(args, ['preloadPath', 'error']);
},
},
};
events = {
app: {
'certificate-error': true,
'child-process-gone': true,
'render-process-gone': true,
},
webContents: {
// 'console-message': true,
'did-fail-load': true,
'did-fail-provisional-load': true,
'plugin-crashed': true,
'preload-error': true,
'unresponsive': true,
},
};
externalApi = undefined;
level = 'error';
scope = '';
constructor(options = {}) {
this.setOptions(options);
}
setOptions({
events,
externalApi,
level,
logger,
format,
formatters,
scope,
}) {
if (typeof events === 'object') {
this.events = events;
}
if (typeof externalApi === 'object') {
this.externalApi = externalApi;
}
if (typeof level === 'string') {
this.level = level;
}
if (typeof logger === 'object') {
this.logger = logger;
}
if (typeof format === 'string' || typeof format === 'function') {
this.format = format;
}
if (typeof formatters === 'object') {
this.formatters = formatters;
}
if (typeof scope === 'string') {
this.scope = scope;
}
}
startLogging(options = {}) {
this.setOptions(options);
this.disposeListeners();
for (const eventName of this.getEventNames(this.events.app)) {
this.disposers.push(
this.externalApi.onAppEvent(eventName, (...handlerArgs) => {
this.handleEvent({ eventSource: 'app', eventName, handlerArgs });
}),
);
}
for (const eventName of this.getEventNames(this.events.webContents)) {
this.disposers.push(
this.externalApi.onEveryWebContentsEvent(
eventName,
(...handlerArgs) => {
this.handleEvent(
{ eventSource: 'webContents', eventName, handlerArgs },
);
},
),
);
}
}
stopLogging() {
this.disposeListeners();
}
arrayToObject(array, fieldNames) {
const obj = {};
fieldNames.forEach((fieldName, index) => {
obj[fieldName] = array[index];
});
if (array.length > fieldNames.length) {
obj.unknownArgs = array.slice(fieldNames.length);
}
return obj;
}
disposeListeners() {
this.disposers.forEach((disposer) => disposer());
this.disposers = [];
}
formatEventLog({ eventName, eventSource, handlerArgs }) {
const [event, ...args] = handlerArgs;
if (typeof this.format === 'function') {
return this.format({ args, event, eventName, eventSource });
}
const formatter = this.formatters[eventSource]?.[eventName];
let formattedArgs = args;
if (typeof formatter === 'function') {
formattedArgs = formatter({ args, event, eventName, eventSource });
}
if (!formattedArgs) {
return undefined;
}
const eventData = {};
if (Array.isArray(formattedArgs)) {
eventData.args = formattedArgs;
} else if (typeof formattedArgs === 'object') {
Object.assign(eventData, formattedArgs);
}
if (eventSource === 'webContents') {
Object.assign(eventData, this.getWebContentsDetails(event?.sender));
}
const title = this.format
.replace('{eventSource}', eventSource === 'app' ? 'App' : 'WebContents')
.replace('{eventName}', eventName);
return [title, eventData];
}
getEventNames(eventMap) {
if (!eventMap || typeof eventMap !== 'object') {
return [];
}
return Object.entries(eventMap)
.filter(([_, listen]) => listen)
.map(([eventName]) => eventName);
}
getWebContentsDetails(webContents) {
if (!webContents?.loadURL) {
return {};
}
try {
return {
webContents: {
id: webContents.id,
url: webContents.getURL(),
},
};
} catch {
return {};
}
}
handleEvent({ eventName, eventSource, handlerArgs }) {
const log = this.formatEventLog({ eventName, eventSource, handlerArgs });
if (log) {
const logFns = this.scope ? this.logger.scope(this.scope) : this.logger;
logFns?.[this.level]?.(...log);
}
}
}
module.exports = EventLogger;

224
mc_test/node_modules/electron-log/src/node/NodeExternalApi.js generated vendored Executable file
View File

@ -0,0 +1,224 @@
'use strict';
/* eslint-disable no-unused-vars */
const childProcess = require('child_process');
const os = require('os');
const path = require('path');
const packageJson = require('./packageJson');
class NodeExternalApi {
appName = undefined;
appPackageJson = undefined;
platform = process.platform;
getAppLogPath(appName = this.getAppName()) {
if (this.platform === 'darwin') {
return path.join(this.getSystemPathHome(), 'Library/Logs', appName);
}
return path.join(this.getAppUserDataPath(appName), 'logs');
}
getAppName() {
const appName = this.appName || this.getAppPackageJson()?.name;
if (!appName) {
throw new Error(
'electron-log can\'t determine the app name. It tried these methods:\n'
+ '1. Use `electron.app.name`\n'
+ '2. Use productName or name from the nearest package.json`\n'
+ 'You can also set it through log.transports.file.setAppName()',
);
}
return appName;
}
/**
* @private
* @returns {undefined}
*/
getAppPackageJson() {
if (typeof this.appPackageJson !== 'object') {
this.appPackageJson = packageJson.findAndReadPackageJson();
}
return this.appPackageJson;
}
getAppUserDataPath(appName = this.getAppName()) {
return appName
? path.join(this.getSystemPathAppData(), appName)
: undefined;
}
getAppVersion() {
return this.getAppPackageJson()?.version;
}
getElectronLogPath() {
return this.getAppLogPath();
}
getMacOsVersion() {
const release = Number(os.release().split('.')[0]);
if (release <= 19) {
return `10.${release - 4}`;
}
return release - 9;
}
/**
* @protected
* @returns {string}
*/
getOsVersion() {
let osName = os.type().replace('_', ' ');
let osVersion = os.release();
if (osName === 'Darwin') {
osName = 'macOS';
osVersion = this.getMacOsVersion();
}
return `${osName} ${osVersion}`;
}
/**
* @return {PathVariables}
*/
getPathVariables() {
const appName = this.getAppName();
const appVersion = this.getAppVersion();
const self = this;
return {
appData: this.getSystemPathAppData(),
appName,
appVersion,
get electronDefaultDir() {
return self.getElectronLogPath();
},
home: this.getSystemPathHome(),
libraryDefaultDir: this.getAppLogPath(appName),
libraryTemplate: this.getAppLogPath('{appName}'),
temp: this.getSystemPathTemp(),
userData: this.getAppUserDataPath(appName),
};
}
getSystemPathAppData() {
const home = this.getSystemPathHome();
switch (this.platform) {
case 'darwin': {
return path.join(home, 'Library/Application Support');
}
case 'win32': {
return process.env.APPDATA || path.join(home, 'AppData/Roaming');
}
default: {
return process.env.XDG_CONFIG_HOME || path.join(home, '.config');
}
}
}
getSystemPathHome() {
return os.homedir?.() || process.env.HOME;
}
getSystemPathTemp() {
return os.tmpdir();
}
getVersions() {
return {
app: `${this.getAppName()} ${this.getAppVersion()}`,
electron: undefined,
os: this.getOsVersion(),
};
}
isDev() {
return process.env.NODE_ENV === 'development'
|| process.env.ELECTRON_IS_DEV === '1';
}
isElectron() {
return Boolean(process.versions.electron);
}
onAppEvent(_eventName, _handler) {
// Ignored in node.js
}
onAppReady(handler) {
handler();
}
onEveryWebContentsEvent(eventName, handler) {
// Ignored in node.js
}
/**
* Listen to async messages sent from opposite process
* @param {string} channel
* @param {function} listener
*/
onIpc(channel, listener) {
// Ignored in node.js
}
onIpcInvoke(channel, listener) {
// Ignored in node.js
}
/**
* @param {string} url
* @param {Function} [logFunction]
*/
openUrl(url, logFunction = console.error) { // eslint-disable-line no-console
const startMap = { darwin: 'open', win32: 'start', linux: 'xdg-open' };
const start = startMap[process.platform] || 'xdg-open';
childProcess.exec(`${start} ${url}`, {}, (err) => {
if (err) {
logFunction(err);
}
});
}
setAppName(appName) {
this.appName = appName;
}
setPlatform(platform) {
this.platform = platform;
}
setPreloadFileForSessions({
filePath, // eslint-disable-line no-unused-vars
includeFutureSession = true, // eslint-disable-line no-unused-vars
getSessions = () => [], // eslint-disable-line no-unused-vars
}) {
// Ignored in node.js
}
/**
* Sent a message to opposite process
* @param {string} channel
* @param {any} message
*/
sendIpc(channel, message) {
// Ignored in node.js
}
showErrorBox(title, message) {
// Ignored in node.js
}
}
module.exports = NodeExternalApi;

View File

@ -0,0 +1,45 @@
'use strict';
const Logger = require('../core/Logger');
const ErrorHandler = require('./ErrorHandler');
const EventLogger = require('./EventLogger');
const transportConsole = require('./transports/console');
const transportFile = require('./transports/file');
const transportIpc = require('./transports/ipc');
const transportRemote = require('./transports/remote');
module.exports = createDefaultLogger;
function createDefaultLogger({ dependencies, initializeFn }) {
const defaultLogger = new Logger({
dependencies,
errorHandler: new ErrorHandler(),
eventLogger: new EventLogger(),
initializeFn,
isDev: dependencies.externalApi?.isDev(),
logId: 'default',
transportFactories: {
console: transportConsole,
file: transportFile,
ipc: transportIpc,
remote: transportRemote,
},
variables: {
processType: 'main',
},
});
defaultLogger.default = defaultLogger;
defaultLogger.Logger = Logger;
defaultLogger.processInternalErrorFn = (e) => {
defaultLogger.transports.console.writeFn({
message: {
data: ['Unhandled electron-log error', e],
level: 'error',
},
});
};
return defaultLogger;
}

12
mc_test/node_modules/electron-log/src/node/index.js generated vendored Executable file
View File

@ -0,0 +1,12 @@
'use strict';
const NodeExternalApi = require('./NodeExternalApi');
const createDefaultLogger = require('./createDefaultLogger');
const externalApi = new NodeExternalApi();
const defaultLogger = createDefaultLogger({
dependencies: { externalApi },
});
module.exports = defaultLogger;

104
mc_test/node_modules/electron-log/src/node/packageJson.js generated vendored Executable file
View File

@ -0,0 +1,104 @@
'use strict';
const fs = require('fs');
const path = require('path');
module.exports = {
findAndReadPackageJson,
tryReadJsonAt,
};
/**
* @return {{ name?: string, version?: string}}
*/
function findAndReadPackageJson() {
return tryReadJsonAt(getMainModulePath())
|| tryReadJsonAt(extractPathFromArgs())
|| tryReadJsonAt(process.resourcesPath, 'app.asar')
|| tryReadJsonAt(process.resourcesPath, 'app')
|| tryReadJsonAt(process.cwd())
|| { name: undefined, version: undefined };
}
/**
* @param {...string} searchPaths
* @return {{ name?: string, version?: string } | undefined}
*/
function tryReadJsonAt(...searchPaths) {
if (!searchPaths[0]) {
return undefined;
}
try {
const searchPath = path.join(...searchPaths);
const fileName = findUp('package.json', searchPath);
if (!fileName) {
return undefined;
}
const json = JSON.parse(fs.readFileSync(fileName, 'utf8'));
const name = json?.productName || json?.name;
if (!name || name.toLowerCase() === 'electron') {
return undefined;
}
if (name) {
return { name, version: json?.version };
}
return undefined;
} catch (e) {
return undefined;
}
}
/**
* @param {string} fileName
* @param {string} [cwd]
* @return {string | null}
*/
function findUp(fileName, cwd) {
let currentPath = cwd;
// eslint-disable-next-line no-constant-condition
while (true) {
const parsedPath = path.parse(currentPath);
const root = parsedPath.root;
const dir = parsedPath.dir;
if (fs.existsSync(path.join(currentPath, fileName))) {
return path.resolve(path.join(currentPath, fileName));
}
if (currentPath === root) {
return null;
}
currentPath = dir;
}
}
/**
* Get app path from --user-data-dir cmd arg, passed to a renderer process
* @return {string|null}
*/
function extractPathFromArgs() {
const matchedArgs = process.argv.filter((arg) => {
return arg.indexOf('--user-data-dir=') === 0;
});
if (matchedArgs.length === 0 || typeof matchedArgs[0] !== 'string') {
return null;
}
const userDataDir = matchedArgs[0];
return userDataDir.replace('--user-data-dir=', '');
}
function getMainModulePath() {
try {
// Requires isn't available in ESM
return require.main?.filename;
} catch {
return undefined;
}
}

View File

@ -0,0 +1,137 @@
'use strict';
const util = require('util');
module.exports = {
serialize,
maxDepth({ data, transport, depth = transport?.depth ?? 6 }) {
if (!data) {
return data;
}
if (depth < 1) {
if (Array.isArray(data)) return '[array]';
if (typeof data === 'object' && data) return '[object]';
return data;
}
if (Array.isArray(data)) {
return data.map((child) => module.exports.maxDepth({
data: child,
depth: depth - 1,
}));
}
if (typeof data !== 'object') {
return data;
}
if (data && typeof data.toISOString === 'function') {
return data;
}
// noinspection PointlessBooleanExpressionJS
if (data === null) {
return null;
}
if (data instanceof Error) {
return data;
}
const newJson = {};
for (const i in data) {
if (!Object.prototype.hasOwnProperty.call(data, i)) continue;
newJson[i] = module.exports.maxDepth({
data: data[i],
depth: depth - 1,
});
}
return newJson;
},
toJSON({ data }) {
return JSON.parse(JSON.stringify(data, createSerializer()));
},
toString({ data, transport }) {
const inspectOptions = transport?.inspectOptions || {};
const simplifiedData = data.map((item) => {
if (item === undefined) {
return undefined;
}
try {
const str = JSON.stringify(item, createSerializer(), ' ');
return str === undefined ? undefined : JSON.parse(str);
} catch (e) {
// There are some rare cases when an item can't be simplified.
// In that case, it's fine to pass it to util.format directly.
return item;
}
});
return util.formatWithOptions(inspectOptions, ...simplifiedData);
},
};
/**
* @param {object} options?
* @param {boolean} options.serializeMapAndSet?
* @return {function}
*/
function createSerializer(options = {}) {
const seen = new WeakSet();
return function (key, value) {
if (typeof value === 'object' && value !== null) {
if (seen.has(value)) {
return undefined;
}
seen.add(value);
}
return serialize(key, value, options);
};
}
/**
* @param {string} key
* @param {any} value
* @param {object} options?
* @return {any}
*/
function serialize(key, value, options = {}) {
const serializeMapAndSet = options?.serializeMapAndSet !== false;
if (value instanceof Error) {
return value.stack;
}
if (!value) {
return value;
}
if (typeof value === 'function') {
return `[function] ${value.toString()}`;
}
if (value instanceof Date) {
return value.toISOString();
}
if (serializeMapAndSet && value instanceof Map && Object.fromEntries) {
return Object.fromEntries(value);
}
if (serializeMapAndSet && value instanceof Set && Array.from) {
return Array.from(value);
}
return value;
}

View File

@ -0,0 +1,94 @@
'use strict';
/* eslint-disable no-console */
const {
concatFirstStringElements,
format,
} = require('../../core/transforms/format');
const { maxDepth, toJSON } = require('../transforms/object');
const {
applyAnsiStyles,
removeStyles,
} = require('../../core/transforms/style');
const { transform } = require('../../core/transforms/transform');
const consoleMethods = {
error: console.error,
warn: console.warn,
info: console.info,
verbose: console.info,
debug: console.debug,
silly: console.debug,
log: console.log,
};
module.exports = consoleTransportFactory;
const separator = process.platform === 'win32' ? '>' : '';
const DEFAULT_FORMAT = `%c{h}:{i}:{s}.{ms}{scope}%c ${separator} {text}`;
Object.assign(consoleTransportFactory, {
DEFAULT_FORMAT,
});
function consoleTransportFactory(logger) {
return Object.assign(transport, {
format: DEFAULT_FORMAT,
level: 'silly',
transforms: [
addTemplateColors,
format,
formatStyles,
concatFirstStringElements,
maxDepth,
toJSON,
],
useStyles: process.env.FORCE_STYLES,
writeFn({ message }) {
const consoleLogFn = consoleMethods[message.level] || consoleMethods.info;
consoleLogFn(...message.data);
},
});
function transport(message) {
const data = transform({ logger, message, transport });
transport.writeFn({
message: { ...message, data },
});
}
}
function addTemplateColors({ data, message, transport }) {
if (
typeof transport.format !== 'string'
|| !transport.format.includes('%c')
) {
return data;
}
return [`color:${levelToStyle(message.level)}`, 'color:unset', ...data];
}
function canUseStyles(useStyleValue, level) {
if (typeof useStyleValue === 'boolean') {
return useStyleValue;
}
const useStderr = level === 'error' || level === 'warn';
const stream = useStderr ? process.stderr : process.stdout;
return stream && stream.isTTY;
}
function formatStyles(args) {
const { message, transport } = args;
const useStyles = canUseStyles(transport.useStyles, message.level);
const nextTransform = useStyles ? applyAnsiStyles : removeStyles;
return nextTransform(args);
}
function levelToStyle(level) {
const map = { error: 'red', warn: 'yellow', info: 'cyan', default: 'unset' };
return map[level] || map.default;
}

View File

@ -0,0 +1,158 @@
'use strict';
const EventEmitter = require('events');
const fs = require('fs');
const os = require('os');
class File extends EventEmitter {
asyncWriteQueue = [];
bytesWritten = 0;
hasActiveAsyncWriting = false;
path = null;
initialSize = undefined;
writeOptions = null;
writeAsync = false;
constructor({
path,
writeOptions = { encoding: 'utf8', flag: 'a', mode: 0o666 },
writeAsync = false,
}) {
super();
this.path = path;
this.writeOptions = writeOptions;
this.writeAsync = writeAsync;
}
get size() {
return this.getSize();
}
clear() {
try {
fs.writeFileSync(this.path, '', {
mode: this.writeOptions.mode,
flag: 'w',
});
this.reset();
return true;
} catch (e) {
if (e.code === 'ENOENT') {
return true;
}
this.emit('error', e, this);
return false;
}
}
crop(bytesAfter) {
try {
const content = readFileSyncFromEnd(this.path, bytesAfter || 4096);
this.clear();
this.writeLine(`[log cropped]${os.EOL}${content}`);
} catch (e) {
this.emit(
'error',
new Error(`Couldn't crop file ${this.path}. ${e.message}`),
this,
);
}
}
getSize() {
if (this.initialSize === undefined) {
try {
const stats = fs.statSync(this.path);
this.initialSize = stats.size;
} catch (e) {
this.initialSize = 0;
}
}
return this.initialSize + this.bytesWritten;
}
increaseBytesWrittenCounter(text) {
this.bytesWritten += Buffer.byteLength(text, this.writeOptions.encoding);
}
isNull() {
return false;
}
nextAsyncWrite() {
const file = this;
if (this.hasActiveAsyncWriting || this.asyncWriteQueue.length === 0) {
return;
}
const text = this.asyncWriteQueue.join('');
this.asyncWriteQueue = [];
this.hasActiveAsyncWriting = true;
fs.writeFile(this.path, text, this.writeOptions, (e) => {
file.hasActiveAsyncWriting = false;
if (e) {
file.emit(
'error',
new Error(`Couldn't write to ${file.path}. ${e.message}`),
this,
);
} else {
file.increaseBytesWrittenCounter(text);
}
file.nextAsyncWrite();
});
}
reset() {
this.initialSize = undefined;
this.bytesWritten = 0;
}
toString() {
return this.path;
}
writeLine(text) {
text += os.EOL;
if (this.writeAsync) {
this.asyncWriteQueue.push(text);
this.nextAsyncWrite();
return;
}
try {
fs.writeFileSync(this.path, text, this.writeOptions);
this.increaseBytesWrittenCounter(text);
} catch (e) {
this.emit(
'error',
new Error(`Couldn't write to ${this.path}. ${e.message}`),
this,
);
}
}
}
module.exports = File;
function readFileSyncFromEnd(filePath, bytesCount) {
const buffer = Buffer.alloc(bytesCount);
const stats = fs.statSync(filePath);
const readLength = Math.min(stats.size, bytesCount);
const offset = Math.max(0, stats.size - bytesCount);
const fd = fs.openSync(filePath, 'r');
const totalBytes = fs.readSync(fd, buffer, 0, readLength, offset);
fs.closeSync(fd);
return buffer.toString('utf8', 0, totalBytes);
}

View File

@ -0,0 +1,76 @@
'use strict';
const EventEmitter = require('events');
const fs = require('fs');
const path = require('path');
const File = require('./File');
const NullFile = require('./NullFile');
class FileRegistry extends EventEmitter {
store = {};
constructor() {
super();
this.emitError = this.emitError.bind(this);
}
/**
* Provide a File object corresponding to the filePath
* @param {string} filePath
* @param {WriteOptions} [writeOptions]
* @param {boolean} [writeAsync]
* @return {File}
*/
provide({ filePath, writeOptions = {}, writeAsync = false }) {
let file;
try {
filePath = path.resolve(filePath);
if (this.store[filePath]) {
return this.store[filePath];
}
file = this.createFile({ filePath, writeOptions, writeAsync });
} catch (e) {
file = new NullFile({ path: filePath });
this.emitError(e, file);
}
file.on('error', this.emitError);
this.store[filePath] = file;
return file;
}
/**
* @param {string} filePath
* @param {WriteOptions} writeOptions
* @param {boolean} async
* @return {File}
* @private
*/
createFile({ filePath, writeOptions, writeAsync }) {
this.testFileWriting({ filePath, writeOptions });
return new File({ path: filePath, writeOptions, writeAsync });
}
/**
* @param {Error} error
* @param {File} file
* @private
*/
emitError(error, file) {
this.emit('error', error, file);
}
/**
* @param {string} filePath
* @param {WriteOptions} writeOptions
* @private
*/
testFileWriting({ filePath, writeOptions }) {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, '', { flag: 'a', mode: writeOptions.mode });
}
}
module.exports = FileRegistry;

View File

@ -0,0 +1,27 @@
'use strict';
const File = require('./File');
class NullFile extends File {
clear() {
}
crop() {
}
getSize() {
return 0;
}
isNull() {
return true;
}
writeLine() {
}
}
module.exports = NullFile;

View File

@ -0,0 +1,165 @@
'use strict';
const fs = require('fs');
const os = require('os');
const path = require('path');
const FileRegistry = require('./FileRegistry');
const { transform } = require('../../../core/transforms/transform');
const { removeStyles } = require('../../../core/transforms/style');
const {
format,
concatFirstStringElements,
} = require('../../../core/transforms/format');
const { toString } = require('../../transforms/object');
module.exports = fileTransportFactory;
// Shared between multiple file transport instances
const globalRegistry = new FileRegistry();
function fileTransportFactory(
logger,
{ registry = globalRegistry, externalApi } = {},
) {
/** @type {PathVariables} */
let pathVariables;
if (registry.listenerCount('error') < 1) {
registry.on('error', (e, file) => {
logConsole(`Can't write to ${file}`, e);
});
}
return Object.assign(transport, {
fileName: getDefaultFileName(logger.variables.processType),
format: '[{y}-{m}-{d} {h}:{i}:{s}.{ms}] [{level}]{scope} {text}',
getFile,
inspectOptions: { depth: 5 },
level: 'silly',
maxSize: 1024 ** 2,
readAllLogs,
sync: true,
transforms: [removeStyles, format, concatFirstStringElements, toString],
writeOptions: { flag: 'a', mode: 0o666, encoding: 'utf8' },
archiveLogFn(file) {
const oldPath = file.toString();
const inf = path.parse(oldPath);
try {
fs.renameSync(oldPath, path.join(inf.dir, `${inf.name}.old${inf.ext}`));
} catch (e) {
logConsole('Could not rotate log', e);
const quarterOfMaxSize = Math.round(transport.maxSize / 4);
file.crop(Math.min(quarterOfMaxSize, 256 * 1024));
}
},
resolvePathFn(vars) {
return path.join(vars.libraryDefaultDir, vars.fileName);
},
setAppName(name) {
logger.dependencies.externalApi.setAppName(name);
},
});
function transport(message) {
const file = getFile(message);
const needLogRotation = transport.maxSize > 0
&& file.size > transport.maxSize;
if (needLogRotation) {
transport.archiveLogFn(file);
file.reset();
}
const content = transform({ logger, message, transport });
file.writeLine(content);
}
function initializeOnFirstAccess() {
if (pathVariables) {
return;
}
// Make a shallow copy of pathVariables to keep getters intact
pathVariables = Object.create(
Object.prototype,
{
...Object.getOwnPropertyDescriptors(
externalApi.getPathVariables(),
),
fileName: {
get() {
return transport.fileName;
},
enumerable: true,
},
},
);
if (typeof transport.archiveLog === 'function') {
transport.archiveLogFn = transport.archiveLog;
logConsole('archiveLog is deprecated. Use archiveLogFn instead');
}
if (typeof transport.resolvePath === 'function') {
transport.resolvePathFn = transport.resolvePath;
logConsole('resolvePath is deprecated. Use resolvePathFn instead');
}
}
function logConsole(message, error = null, level = 'error') {
const data = [`electron-log.transports.file: ${message}`];
if (error) {
data.push(error);
}
logger.transports.console({ data, date: new Date(), level });
}
function getFile(msg) {
initializeOnFirstAccess();
const filePath = transport.resolvePathFn(pathVariables, msg);
return registry.provide({
filePath,
writeAsync: !transport.sync,
writeOptions: transport.writeOptions,
});
}
function readAllLogs({ fileFilter = (f) => f.endsWith('.log') } = {}) {
initializeOnFirstAccess();
const logsPath = path.dirname(transport.resolvePathFn(pathVariables));
if (!fs.existsSync(logsPath)) {
return [];
}
return fs.readdirSync(logsPath)
.map((fileName) => path.join(logsPath, fileName))
.filter(fileFilter)
.map((logPath) => {
try {
return {
path: logPath,
lines: fs.readFileSync(logPath, 'utf8').split(os.EOL),
};
} catch {
return null;
}
})
.filter(Boolean);
}
}
function getDefaultFileName(processType = process.type) {
switch (processType) {
case 'renderer': return 'renderer.log';
case 'worker': return 'worker.log';
default: return 'main.log';
}
}

33
mc_test/node_modules/electron-log/src/node/transports/ipc.js generated vendored Executable file
View File

@ -0,0 +1,33 @@
'use strict';
const { maxDepth, toJSON } = require('../transforms/object');
const { transform } = require('../../core/transforms/transform');
module.exports = ipcTransportFactory;
/**
* @param logger
* @param {ElectronExternalApi} externalApi
* @returns {transport|null}
*/
function ipcTransportFactory(logger, { externalApi }) {
Object.assign(transport, {
depth: 3,
eventId: '__ELECTRON_LOG_IPC__',
level: logger.isDev ? 'silly' : false,
transforms: [toJSON, maxDepth],
});
return externalApi?.isElectron() ? transport : undefined;
function transport(message) {
if (message?.variables?.processType === 'renderer') {
return;
}
externalApi?.sendIpc(transport.eventId, {
...message,
data: transform({ logger, message, transport }),
});
}
}

View File

@ -0,0 +1,85 @@
'use strict';
const http = require('http');
const https = require('https');
const { transform } = require('../../core/transforms/transform');
const { removeStyles } = require('../../core/transforms/style');
const { toJSON, maxDepth } = require('../transforms/object');
module.exports = remoteTransportFactory;
function remoteTransportFactory(logger) {
return Object.assign(transport, {
client: { name: 'electron-application' },
depth: 6,
level: false,
requestOptions: {},
transforms: [removeStyles, toJSON, maxDepth],
makeBodyFn({ message }) {
return JSON.stringify({
client: transport.client,
data: message.data,
date: message.date.getTime(),
level: message.level,
scope: message.scope,
variables: message.variables,
});
},
processErrorFn({ error }) {
logger.processMessage(
{
data: [`electron-log: can't POST ${transport.url}`, error],
level: 'warn',
},
{ transports: ['console', 'file'] },
);
},
sendRequestFn({ serverUrl, requestOptions, body }) {
const httpTransport = serverUrl.startsWith('https:') ? https : http;
const request = httpTransport.request(serverUrl, {
method: 'POST',
...requestOptions,
headers: {
'Content-Type': 'application/json',
'Content-Length': body.length,
...requestOptions.headers,
},
});
request.write(body);
request.end();
return request;
},
});
function transport(message) {
if (!transport.url) {
return;
}
const body = transport.makeBodyFn({
logger,
message: { ...message, data: transform({ logger, message, transport }) },
transport,
});
const request = transport.sendRequestFn({
serverUrl: transport.url,
requestOptions: transport.requestOptions,
body: Buffer.from(body, 'utf8'),
});
request.on('error', (error) => transport.processErrorFn({
error,
logger,
message,
request,
transport,
}));
}
}

View File

@ -0,0 +1,83 @@
'use strict';
let electron = {};
try {
// eslint-disable-next-line global-require,import/no-extraneous-dependencies
electron = require('electron');
} catch (e) {
// require isn't available, not from a preload script
}
if (electron.ipcRenderer) {
initialize(electron);
}
if (typeof module === 'object') {
module.exports = initialize;
}
/**
* @param {Electron.ContextBridge} contextBridge
* @param {Electron.IpcRenderer} ipcRenderer
*/
function initialize({ contextBridge, ipcRenderer }) {
if (!ipcRenderer) {
return;
}
ipcRenderer.on('__ELECTRON_LOG_IPC__', (_, message) => {
window.postMessage({ cmd: 'message', ...message });
});
ipcRenderer
.invoke('__ELECTRON_LOG__', { cmd: 'getOptions' })
// eslint-disable-next-line no-console
.catch((e) => console.error(new Error(
'electron-log isn\'t initialized in the main process. '
+ `Please call log.initialize() before. ${e.message}`,
)));
const electronLog = {
sendToMain(message) {
try {
ipcRenderer.send('__ELECTRON_LOG__', message);
} catch (e) {
// eslint-disable-next-line no-console
console.error('electronLog.sendToMain ', e, 'data:', message);
ipcRenderer.send('__ELECTRON_LOG__', {
cmd: 'errorHandler',
error: { message: e?.message, stack: e?.stack },
errorName: 'sendToMain',
});
}
},
log(...data) {
electronLog.sendToMain({ data, level: 'info' });
},
};
for (const level of ['error', 'warn', 'info', 'verbose', 'debug', 'silly']) {
electronLog[level] = (...data) => electronLog.sendToMain({
data,
level,
});
}
if (contextBridge && process.contextIsolated) {
try {
contextBridge.exposeInMainWorld('__electronLog', electronLog);
} catch {
// Sometimes this files can be included twice
}
}
if (typeof window === 'object') {
window.__electronLog = electronLog;
} else {
// noinspection JSConstantReassignment
__electronLog = electronLog;
}
}

78
mc_test/node_modules/electron-log/src/renderer/index.js generated vendored Executable file
View File

@ -0,0 +1,78 @@
'use strict';
const Logger = require('../core/Logger');
const RendererErrorHandler = require('./lib/RendererErrorHandler');
const transportConsole = require('./lib/transports/console');
const transportIpc = require('./lib/transports/ipc');
if (typeof process === 'object' && process.type === 'browser') {
// eslint-disable-next-line no-console
console.warn(
'electron-log/renderer is loaded in the main process. '
+ 'It could cause unexpected behaviour.',
);
}
module.exports = createLogger();
module.exports.Logger = Logger;
module.exports.default = module.exports;
function createLogger() {
const logger = new Logger({
allowUnknownLevel: true,
errorHandler: new RendererErrorHandler(),
initializeFn: () => {},
logId: 'default',
transportFactories: {
console: transportConsole,
ipc: transportIpc,
},
variables: {
processType: 'renderer',
},
});
logger.errorHandler.setOptions({
logFn({ error, errorName, showDialog }) {
logger.transports.console({
data: [errorName, error].filter(Boolean),
level: 'error',
});
logger.transports.ipc({
cmd: 'errorHandler',
error: {
cause: error?.cause,
code: error?.code,
name: error?.name,
message: error?.message,
stack: error?.stack,
},
errorName,
logId: logger.logId,
showDialog,
});
},
});
if (typeof window === 'object') {
window.addEventListener('message', (event) => {
const { cmd, logId, ...message } = event.data || {};
const instance = Logger.getInstance({ logId });
if (cmd === 'message') {
instance.processMessage(message, { transports: ['console'] });
}
});
}
// To support custom levels
return new Proxy(logger, {
get(target, prop) {
if (typeof target[prop] !== 'undefined') {
return target[prop];
}
return (...data) => logger.logData(data, { level: prop });
},
});
}

View File

@ -0,0 +1,82 @@
'use strict';
// eslint-disable-next-line no-console
const consoleError = console.error;
class RendererErrorHandler {
logFn = null;
onError = null;
showDialog = false;
preventDefault = true;
constructor({ logFn = null } = {}) {
this.handleError = this.handleError.bind(this);
this.handleRejection = this.handleRejection.bind(this);
this.startCatching = this.startCatching.bind(this);
this.logFn = logFn;
}
handle(error, {
logFn = this.logFn,
errorName = '',
onError = this.onError,
showDialog = this.showDialog,
} = {}) {
try {
if (onError?.({ error, errorName, processType: 'renderer' }) !== false) {
logFn({ error, errorName, showDialog });
}
} catch {
consoleError(error);
}
}
setOptions({ logFn, onError, preventDefault, showDialog }) {
if (typeof logFn === 'function') {
this.logFn = logFn;
}
if (typeof onError === 'function') {
this.onError = onError;
}
if (typeof preventDefault === 'boolean') {
this.preventDefault = preventDefault;
}
if (typeof showDialog === 'boolean') {
this.showDialog = showDialog;
}
}
startCatching({ onError, showDialog } = {}) {
if (this.isActive) {
return;
}
this.isActive = true;
this.setOptions({ onError, showDialog });
window.addEventListener('error', (event) => {
this.preventDefault && event.preventDefault?.();
this.handleError(event.error || event);
});
window.addEventListener('unhandledrejection', (event) => {
this.preventDefault && event.preventDefault?.();
this.handleRejection(event.reason || event);
});
}
handleError(error) {
this.handle(error, { errorName: 'Unhandled' });
}
handleRejection(reason) {
const error = reason instanceof Error
? reason
: new Error(JSON.stringify(reason));
this.handle(error, { errorName: 'Unhandled rejection' });
}
}
module.exports = RendererErrorHandler;

View File

@ -0,0 +1,95 @@
'use strict';
/* eslint-disable no-console */
const { transform } = require('../../../core/transforms/transform');
module.exports = consoleTransportRendererFactory;
const consoleMethods = {
error: console.error,
warn: console.warn,
info: console.info,
verbose: console.info,
debug: console.debug,
silly: console.debug,
log: console.log,
};
function consoleTransportRendererFactory(logger) {
return Object.assign(transport, {
format: '{h}:{i}:{s}.{ms}{scope} {text}',
transforms: [formatDataFn],
writeFn({ message: { level, data } }) {
const consoleLogFn = consoleMethods[level] || consoleMethods.info;
// make an empty call stack
setTimeout(() => consoleLogFn(...data));
},
});
function transport(message) {
transport.writeFn({
message: { ...message, data: transform({ logger, message, transport }) },
});
}
}
function formatDataFn({
data = [],
logger = {},
message = {},
transport = {},
}) {
if (typeof transport.format === 'function') {
return transport.format({
data,
level: message?.level || 'info',
logger,
message,
transport,
});
}
if (typeof transport.format !== 'string') {
return data;
}
data.unshift(transport.format);
// Concatenate the first two data items to support printf-like templates
if (typeof data[1] === 'string' && data[1].match(/%[1cdfiOos]/)) {
data = [`${data[0]}${data[1]}`, ...data.slice(2)];
}
const date = message.date || new Date();
data[0] = data[0]
.replace(/\{(\w+)}/g, (substring, name) => {
switch (name) {
case 'level': return message.level;
case 'logId': return message.logId;
case 'scope': {
const scope = message.scope || logger.scope?.defaultLabel;
return scope ? ` (${scope})` : '';
}
case 'text': return '';
case 'y': return date.getFullYear().toString(10);
case 'm': return (date.getMonth() + 1).toString(10)
.padStart(2, '0');
case 'd': return date.getDate().toString(10).padStart(2, '0');
case 'h': return date.getHours().toString(10).padStart(2, '0');
case 'i': return date.getMinutes().toString(10).padStart(2, '0');
case 's': return date.getSeconds().toString(10).padStart(2, '0');
case 'ms': return date.getMilliseconds().toString(10)
.padStart(3, '0');
case 'iso': return date.toISOString();
default: return message.variables?.[name] || substring;
}
})
.trim();
return data;
}

View File

@ -0,0 +1,137 @@
'use strict';
const { transform } = require('../../../core/transforms/transform');
module.exports = ipcTransportRendererFactory;
const RESTRICTED_TYPES = new Set([Promise, WeakMap, WeakSet]);
function ipcTransportRendererFactory(logger) {
return Object.assign(transport, {
depth: 5,
transforms: [serializeFn],
});
function transport(message) {
if (!window.__electronLog) {
logger.processMessage(
{
data: ['electron-log: logger isn\'t initialized in the main process'],
level: 'error',
},
{ transports: ['console'] },
);
return;
}
try {
const serialized = transform({
initialData: message,
logger,
message,
transport,
});
__electronLog.sendToMain(serialized);
} catch (e) {
logger.transports.console({
data: ['electronLog.transports.ipc', e, 'data:', message.data],
level: 'error',
});
}
}
}
/**
* Is type primitive, including null and undefined
* @param {any} value
* @returns {boolean}
*/
function isPrimitive(value) {
return Object(value) !== value;
}
function serializeFn({
data,
depth,
seen = new WeakSet(),
transport = {},
} = {}) {
const actualDepth = depth || transport.depth || 5;
if (seen.has(data)) {
return '[Circular]';
}
if (actualDepth < 1) {
if (isPrimitive(data)) {
return data;
}
if (Array.isArray(data)) {
return '[Array]';
}
return `[${typeof data}]`;
}
if (['function', 'symbol'].includes(typeof data)) {
return data.toString();
}
if (isPrimitive(data)) {
return data;
}
// Object types
if (RESTRICTED_TYPES.has(data.constructor)) {
return `[${data.constructor.name}]`;
}
if (Array.isArray(data)) {
return data.map((item) => serializeFn({
data: item,
depth: actualDepth - 1,
seen,
}));
}
if (data instanceof Date) {
return data.toISOString();
}
if (data instanceof Error) {
return data.stack;
}
if (data instanceof Map) {
return new Map(
Array
.from(data)
.map(([key, value]) => [
serializeFn({ data: key, depth: actualDepth - 1, seen }),
serializeFn({ data: value, depth: actualDepth - 1, seen }),
]),
);
}
if (data instanceof Set) {
return new Set(
Array.from(data).map(
(val) => serializeFn({ data: val, depth: actualDepth - 1, seen }),
),
);
}
seen.add(data);
return Object.fromEntries(
Object.entries(data).map(
([key, value]) => [
key,
serializeFn({ data: value, depth: actualDepth - 1, seen }),
],
),
);
}