mirror of
https://github.com/ClaytonWWilson/stokpile.git
synced 2025-12-15 23:48:50 +00:00
Refactor codebase to improve output flexibility
This commit is contained in:
parent
d4e976c6c4
commit
abb548f5ec
296
src/Logger.ts
296
src/Logger.ts
@ -1,287 +1,63 @@
|
||||
import {
|
||||
LogLabel,
|
||||
LogLevel,
|
||||
StrictLogConfig,
|
||||
StrictLogOutputs,
|
||||
} from "./types/logger";
|
||||
import { gzip, randomString, stringifyInstance, ungzip } from "./lib/utilities";
|
||||
|
||||
import { LogContext, BucketInfo, LogMeta, LogConfig } from "./types/logger";
|
||||
|
||||
const MESSAGE_STYLE = "background: inherit; color: inherit;";
|
||||
|
||||
function getLabel(level: number) {
|
||||
if (level <= LogLevel.TRACE) {
|
||||
return LogLabel.TRACE;
|
||||
} else if (level <= LogLevel.DEBUG) {
|
||||
return LogLabel.DEBUG;
|
||||
} else if (level <= LogLevel.INFO) {
|
||||
return LogLabel.INFO;
|
||||
} else if (level <= LogLevel.WARN) {
|
||||
return LogLabel.WARN;
|
||||
} else {
|
||||
return LogLabel.FATAL;
|
||||
}
|
||||
}
|
||||
import { LogContext, LogLevel, LogMeta } from "./types/logger";
|
||||
import { Loggable, Storable } from "./interface/output";
|
||||
|
||||
export class Logger {
|
||||
private buffer: string[];
|
||||
private bufferLength: number;
|
||||
private bucketIndex: BucketInfo[];
|
||||
private outputs: StrictLogOutputs;
|
||||
private bufferCapacity: number;
|
||||
private outputs: Loggable[] = [];
|
||||
private storage: Storable | undefined;
|
||||
constructor() {}
|
||||
|
||||
constructor(config: LogConfig = {}) {
|
||||
this.buffer = [];
|
||||
this.bufferLength = 0;
|
||||
const parsedConfig = StrictLogConfig.parse(config);
|
||||
this.bufferCapacity = parsedConfig.bufferCapacity;
|
||||
this.outputs = parsedConfig.outputs;
|
||||
|
||||
if (this.outputs.tampermonkey.enabled) {
|
||||
this.bucketIndex = JSON.parse(
|
||||
GM_getValue(this.outputs.tampermonkey.bucketIndexKey, "[]")
|
||||
);
|
||||
} else {
|
||||
this.bucketIndex = [];
|
||||
}
|
||||
addOutput(output: Loggable) {
|
||||
this.outputs.push(output);
|
||||
return this;
|
||||
}
|
||||
|
||||
log(message: string, context: LogContext = {}) {
|
||||
const level = context.level ? context.level : LogLevel.FATAL;
|
||||
const label = getLabel(level);
|
||||
setStorage(storage: Storable) {
|
||||
this.storage = storage;
|
||||
return this;
|
||||
}
|
||||
|
||||
ok() {
|
||||
// TODO: Check all outputs and storage for required props
|
||||
return this;
|
||||
}
|
||||
|
||||
log(message: string, level: LogLevel, context: LogContext) {
|
||||
// const label = getLabel(level);
|
||||
|
||||
const meta: LogMeta = {
|
||||
context,
|
||||
time: new Date().valueOf(),
|
||||
level,
|
||||
time: new Date(),
|
||||
};
|
||||
|
||||
if (this.outputs.console.enabled) {
|
||||
this.consolePrint(label, message, meta);
|
||||
for (const output of this.outputs) {
|
||||
output.write(message, meta, context);
|
||||
}
|
||||
|
||||
const textOutput = `${new Date(
|
||||
meta.time
|
||||
).toISOString()} [${label}] ${message} - ${stringifyInstance(
|
||||
meta.context
|
||||
)}`;
|
||||
|
||||
this.buffer.push(textOutput);
|
||||
this.bufferLength += textOutput.length;
|
||||
|
||||
if (this.outputs.callback) {
|
||||
this.outputs.callback(textOutput);
|
||||
}
|
||||
|
||||
if (this.bufferLength >= this.bufferCapacity) {
|
||||
if (this.outputs.tampermonkey.enabled) {
|
||||
this.flush();
|
||||
} else {
|
||||
while (this.bufferLength >= this.bufferCapacity) {
|
||||
const stale = this.buffer.shift();
|
||||
const offset = stale ? stale.length : 0;
|
||||
this.bufferLength -= offset;
|
||||
}
|
||||
}
|
||||
if (this.storage) {
|
||||
this.storage.write(message, meta, context);
|
||||
}
|
||||
}
|
||||
|
||||
trace(message: string, context?: Object) {
|
||||
this.log(message, {
|
||||
level: LogLevel.TRACE,
|
||||
trace(message: string, context: LogContext = {}) {
|
||||
this.log(message, LogLevel.TRACE, {
|
||||
stacktrace: new Error().stack?.slice(13), // Remove the "Error\n at "
|
||||
...context,
|
||||
});
|
||||
}
|
||||
|
||||
debug(message: string, context?: Object) {
|
||||
this.log(message, { level: LogLevel.DEBUG, ...context });
|
||||
debug(message: string, context: LogContext = {}) {
|
||||
this.log(message, LogLevel.DEBUG, context);
|
||||
}
|
||||
|
||||
info(message: string, context?: Object) {
|
||||
this.log(message, { level: LogLevel.INFO, ...context });
|
||||
info(message: string, context: LogContext = {}) {
|
||||
this.log(message, LogLevel.INFO, context);
|
||||
}
|
||||
|
||||
warn(message: string, context?: Object) {
|
||||
this.log(message, { level: LogLevel.WARN, ...context });
|
||||
warn(message: string, context: LogContext = {}) {
|
||||
this.log(message, LogLevel.WARN, context);
|
||||
}
|
||||
|
||||
fatal(message: string, context?: Object) {
|
||||
this.log(message, { level: LogLevel.FATAL, ...context });
|
||||
}
|
||||
|
||||
private consolePrint(label: LogLabel, message: string, meta: LogMeta) {
|
||||
const styleFormatter = `background: ${this.outputs.console.style[label].backgroundColor}; color: ${this.outputs.console.style[label].textColor}; font-weight: bold; border-radius: 4px;`;
|
||||
|
||||
switch (label) {
|
||||
case LogLabel.TRACE:
|
||||
console.trace(
|
||||
`%c ${label} ` + `%c ${message}`,
|
||||
styleFormatter,
|
||||
MESSAGE_STYLE,
|
||||
meta
|
||||
);
|
||||
break;
|
||||
case LogLabel.DEBUG:
|
||||
console.debug(
|
||||
`%c ${label} ` + `%c ${message}`,
|
||||
styleFormatter,
|
||||
MESSAGE_STYLE,
|
||||
meta
|
||||
);
|
||||
break;
|
||||
case LogLabel.INFO:
|
||||
console.info(
|
||||
`%c ${label} ` + `%c ${message}`,
|
||||
styleFormatter,
|
||||
MESSAGE_STYLE,
|
||||
meta
|
||||
);
|
||||
break;
|
||||
case LogLabel.WARN:
|
||||
console.warn(
|
||||
`%c ${label} ` + `%c ${message}`,
|
||||
styleFormatter,
|
||||
MESSAGE_STYLE,
|
||||
meta
|
||||
);
|
||||
break;
|
||||
case LogLabel.FATAL:
|
||||
console.error(
|
||||
`%c ${label} ` + `%c ${message}`,
|
||||
styleFormatter,
|
||||
MESSAGE_STYLE,
|
||||
meta
|
||||
);
|
||||
break;
|
||||
default:
|
||||
console.log(
|
||||
`%c ${label} ` + `%c ${message}`,
|
||||
styleFormatter,
|
||||
MESSAGE_STYLE,
|
||||
meta
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
async flush() {
|
||||
// Clear buffer
|
||||
const stringifiedBuffer = JSON.stringify(this.buffer);
|
||||
this.buffer = [];
|
||||
this.bufferLength = 0;
|
||||
|
||||
// Don't flush unless tampermonkey output is enabled
|
||||
if (!this.outputs.tampermonkey.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate non-clashing name
|
||||
let newBucketName = randomString(10).toLowerCase();
|
||||
while (GM_getValue(newBucketName, undefined) !== undefined) {
|
||||
newBucketName = randomString(10);
|
||||
}
|
||||
|
||||
// GZip data
|
||||
const gzipped = await gzip(stringifiedBuffer);
|
||||
|
||||
// Update bucketIndex with info
|
||||
const newBucket: BucketInfo = {
|
||||
name: newBucketName,
|
||||
size: gzipped.length,
|
||||
createdAt: new Date().valueOf(),
|
||||
};
|
||||
|
||||
// Write bucketIndex to disk
|
||||
this.bucketIndex.push(newBucket);
|
||||
GM_setValue(
|
||||
this.outputs.tampermonkey.bucketIndexKey,
|
||||
JSON.stringify(this.bucketIndex)
|
||||
);
|
||||
|
||||
// Write gzipped data to new bucket
|
||||
GM_setValue(newBucketName, gzipped);
|
||||
|
||||
if (this.bucketIndex.length <= this.outputs.tampermonkey.maxBuckets) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete old buckets if the number is too large
|
||||
let oldBuckets = this.bucketIndex
|
||||
.sort((a, b) => a.createdAt - b.createdAt)
|
||||
.slice(0, -this.bufferCapacity);
|
||||
|
||||
oldBuckets.forEach((oldBucket) => {
|
||||
GM_deleteValue(oldBucket.name);
|
||||
let deleteIndex = this.bucketIndex.findIndex(
|
||||
(indexBucket) => indexBucket.name === oldBucket.name
|
||||
);
|
||||
|
||||
if (deleteIndex === -1) {
|
||||
console.error("Invalid index for bucket");
|
||||
return;
|
||||
}
|
||||
|
||||
this.bucketIndex.splice(deleteIndex, 1);
|
||||
});
|
||||
|
||||
// Update tampermonkey bucket index
|
||||
GM_setValue(
|
||||
this.outputs.tampermonkey.bucketIndexKey,
|
||||
JSON.stringify(this.bucketIndex)
|
||||
);
|
||||
}
|
||||
|
||||
async export(amount: number) {
|
||||
// Check if the buffer has the requested amount
|
||||
if (this.buffer.length >= amount) {
|
||||
return this.buffer.slice(this.buffer.length - amount);
|
||||
}
|
||||
|
||||
// Only return buffer if tamppermonkey is disabled
|
||||
if (!this.outputs.tampermonkey.enabled) {
|
||||
return [...this.buffer];
|
||||
}
|
||||
|
||||
let logs = [...this.buffer];
|
||||
|
||||
for (const bucket of this.bucketIndex) {
|
||||
// Get data from bucket
|
||||
const gzipped = GM_getValue(bucket.name, undefined);
|
||||
if (gzipped === undefined) {
|
||||
console.error("Bucket does not exist on disk", bucket);
|
||||
continue;
|
||||
}
|
||||
// Ungzip and parse
|
||||
const ungzipped = await ungzip(gzipped);
|
||||
let lines: string[] = [];
|
||||
try {
|
||||
lines = JSON.parse(ungzipped) as string[];
|
||||
} catch (err) {
|
||||
// Bucket has invalid or empty data
|
||||
lines = [];
|
||||
}
|
||||
// prepend to logs up to amount
|
||||
if (logs.length + lines.length < amount) {
|
||||
// Need to grab more from storage
|
||||
logs.unshift(...lines);
|
||||
} else if (logs.length + lines.length == amount) {
|
||||
// Have the exact amount
|
||||
logs.unshift(...lines);
|
||||
break;
|
||||
} else {
|
||||
// Grab a slice of the exact amount needed
|
||||
logs.unshift(...lines.slice(0, amount - logs.length));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return logs;
|
||||
}
|
||||
|
||||
async exportGzipped(amount: number) {
|
||||
const lines = await this.export(amount);
|
||||
const gzipped = await gzip(JSON.stringify(lines));
|
||||
return gzipped;
|
||||
fatal(message: string, context: LogContext = {}) {
|
||||
this.log(message, LogLevel.FATAL, context);
|
||||
}
|
||||
}
|
||||
|
||||
11
src/interface/output.ts
Normal file
11
src/interface/output.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { LogContext, LogMeta } from "../types/logger";
|
||||
|
||||
export abstract class Loggable {
|
||||
abstract write(message: string, meta: LogMeta, context: LogContext): void;
|
||||
}
|
||||
|
||||
export abstract class Storable extends Loggable {
|
||||
abstract read(
|
||||
entries: number
|
||||
): Promise<{ message: string; meta: LogMeta; context: LogContext }[]>;
|
||||
}
|
||||
@ -1,3 +1,5 @@
|
||||
import { LogLabel, LogLevel } from "logger";
|
||||
|
||||
export function blobToBase64(blob: Blob) {
|
||||
return new Promise<string | ArrayBuffer>((resolve, _) => {
|
||||
const reader = new FileReader();
|
||||
@ -71,3 +73,17 @@ export function randomString(length: number) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function getLabel(level: number) {
|
||||
if (level <= LogLevel.TRACE) {
|
||||
return LogLabel.TRACE;
|
||||
} else if (level <= LogLevel.DEBUG) {
|
||||
return LogLabel.DEBUG;
|
||||
} else if (level <= LogLevel.INFO) {
|
||||
return LogLabel.INFO;
|
||||
} else if (level <= LogLevel.WARN) {
|
||||
return LogLabel.WARN;
|
||||
} else {
|
||||
return LogLabel.FATAL;
|
||||
}
|
||||
}
|
||||
|
||||
76
src/outputs/Console.ts
Normal file
76
src/outputs/Console.ts
Normal file
@ -0,0 +1,76 @@
|
||||
import { LogContext, LogLabel, LogMeta } from "../types/logger";
|
||||
import { Loggable } from "../interface/output";
|
||||
import {
|
||||
ConsoleOutputConfig,
|
||||
StrictConsoleOutputConfig,
|
||||
} from "../types/output";
|
||||
import { getLabel } from "../lib/utilities";
|
||||
|
||||
const MESSAGE_STYLE = "background: inherit; color: inherit;";
|
||||
|
||||
export default class Console implements Loggable {
|
||||
private style;
|
||||
enabled: boolean;
|
||||
constructor(config: ConsoleOutputConfig = {}) {
|
||||
const parsedConfig = StrictConsoleOutputConfig.parse(config);
|
||||
this.style = parsedConfig.style;
|
||||
this.enabled = parsedConfig.enabled;
|
||||
}
|
||||
write(message: string, meta: LogMeta, context: LogContext): void {
|
||||
if (!this.enabled) return;
|
||||
|
||||
const label = getLabel(meta.level);
|
||||
const styleFormatter = `background: ${this.style[label].backgroundColor}; color: ${this.style[label].textColor}; font-weight: bold; border-radius: 4px;`;
|
||||
|
||||
switch (label) {
|
||||
case LogLabel.TRACE:
|
||||
console.trace(
|
||||
`%c ${label} ` + `%c ${message}`,
|
||||
styleFormatter,
|
||||
MESSAGE_STYLE,
|
||||
context
|
||||
);
|
||||
break;
|
||||
case LogLabel.DEBUG:
|
||||
console.debug(
|
||||
`%c ${label} ` + `%c ${message}`,
|
||||
styleFormatter,
|
||||
MESSAGE_STYLE,
|
||||
context
|
||||
);
|
||||
break;
|
||||
case LogLabel.INFO:
|
||||
console.info(
|
||||
`%c ${label} ` + `%c ${message}`,
|
||||
styleFormatter,
|
||||
MESSAGE_STYLE,
|
||||
context
|
||||
);
|
||||
break;
|
||||
case LogLabel.WARN:
|
||||
console.warn(
|
||||
`%c ${label} ` + `%c ${message}`,
|
||||
styleFormatter,
|
||||
MESSAGE_STYLE,
|
||||
context
|
||||
);
|
||||
break;
|
||||
case LogLabel.FATAL:
|
||||
console.error(
|
||||
`%c ${label} ` + `%c ${message}`,
|
||||
styleFormatter,
|
||||
MESSAGE_STYLE,
|
||||
context
|
||||
);
|
||||
break;
|
||||
default:
|
||||
console.log(
|
||||
`%c ${label} ` + `%c ${message}`,
|
||||
styleFormatter,
|
||||
MESSAGE_STYLE,
|
||||
context
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
142
src/outputs/Tampermonkey.ts
Normal file
142
src/outputs/Tampermonkey.ts
Normal file
@ -0,0 +1,142 @@
|
||||
import { Storable } from "../interface/output";
|
||||
import {
|
||||
StrictTampermonkeyOutputConfig,
|
||||
TampermonkeyBucketInfo,
|
||||
TampermonkeyOutputConfig,
|
||||
} from "../types/output";
|
||||
import { gzip, randomString, ungzip } from "../lib/utilities";
|
||||
import { LogContext, LogData, LogMeta } from "../types/logger";
|
||||
|
||||
export default class Tampermonkey implements Storable {
|
||||
private buffer: LogData[];
|
||||
private bucketList: TampermonkeyBucketInfo[];
|
||||
private bufferCapacity: number;
|
||||
private bucketListKey: string;
|
||||
private maxBuckets: number;
|
||||
enabled: boolean;
|
||||
|
||||
constructor(config: TampermonkeyOutputConfig = {}) {
|
||||
this.buffer = [];
|
||||
|
||||
const parsedConfig = StrictTampermonkeyOutputConfig.parse(config);
|
||||
this.bucketListKey = parsedConfig.bucketListKey;
|
||||
this.enabled = parsedConfig.enabled;
|
||||
this.bufferCapacity = parsedConfig.bufferCapacity;
|
||||
this.maxBuckets = parsedConfig.maxBuckets;
|
||||
|
||||
this.bucketList = GM_getValue(this.bucketListKey, []);
|
||||
}
|
||||
|
||||
write(message: string, meta: LogMeta, context: LogContext): void {
|
||||
if (!this.enabled) return;
|
||||
this.buffer.push({ message, meta, context });
|
||||
|
||||
if (this.buffer.length > this.bufferCapacity) {
|
||||
this.flush();
|
||||
}
|
||||
}
|
||||
|
||||
async read(
|
||||
entries: number
|
||||
): Promise<{ message: string; meta: LogMeta; context: LogContext }[]> {
|
||||
if (!this.enabled) return Promise.resolve([]);
|
||||
|
||||
// Check if the buffer has the requested amount
|
||||
if (this.buffer.length >= entries) {
|
||||
return Promise.resolve(this.buffer.slice(this.buffer.length - entries));
|
||||
}
|
||||
|
||||
let logs = [...this.buffer];
|
||||
|
||||
for (const bucket of this.bucketList) {
|
||||
// Get data from bucket
|
||||
const gzipped = <string | undefined>GM_getValue(bucket.name, undefined);
|
||||
if (gzipped === undefined) {
|
||||
console.error("Bucket does not exist on disk", bucket);
|
||||
continue;
|
||||
}
|
||||
// Ungzip and parse
|
||||
const ungzipped = await ungzip(gzipped);
|
||||
let lines: LogData[];
|
||||
try {
|
||||
lines = JSON.parse(ungzipped) as LogData[];
|
||||
} catch (err) {
|
||||
// Bucket has invalid or empty data
|
||||
lines = [];
|
||||
}
|
||||
// prepend to logs up to amount
|
||||
if (logs.length + lines.length < entries) {
|
||||
// TODO: Need to grab more from storage
|
||||
logs.unshift(...lines);
|
||||
} else if (logs.length + lines.length == entries) {
|
||||
// Have the exact amount
|
||||
logs.unshift(...lines);
|
||||
break;
|
||||
} else {
|
||||
// Grab a slice of the exact amount needed
|
||||
logs.unshift(...lines.slice(0, entries - logs.length));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return logs;
|
||||
}
|
||||
|
||||
async flush() {
|
||||
// Clear buffer
|
||||
const stringifiedBuffer = JSON.stringify(this.buffer);
|
||||
this.buffer = [];
|
||||
|
||||
// Don't flush unless tampermonkey output is enabled
|
||||
if (!this.enabled) return;
|
||||
|
||||
// Generate non-clashing name
|
||||
let newBucketName = randomString(10).toLowerCase();
|
||||
while (GM_getValue(newBucketName, undefined) !== undefined) {
|
||||
newBucketName = randomString(10);
|
||||
}
|
||||
|
||||
// GZip data
|
||||
const gzipped = await gzip(stringifiedBuffer);
|
||||
|
||||
// Update bucketList with info
|
||||
const newBucket: TampermonkeyBucketInfo = {
|
||||
name: newBucketName,
|
||||
size: gzipped.length,
|
||||
createdAt: new Date().valueOf(),
|
||||
};
|
||||
|
||||
// Write bucketList to disk
|
||||
this.bucketList.push(newBucket);
|
||||
GM_setValue(this.bucketListKey, this.bucketList);
|
||||
|
||||
// Write gzipped data to new bucket
|
||||
GM_setValue(newBucketName, gzipped);
|
||||
|
||||
if (this.bucketList.length <= this.maxBuckets) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete old buckets if the number is too large
|
||||
let oldBuckets = this.bucketList
|
||||
.sort((a, b) => a.createdAt - b.createdAt)
|
||||
.slice(0, -this.bufferCapacity);
|
||||
|
||||
oldBuckets.forEach((oldBucket) => {
|
||||
GM_deleteValue(oldBucket.name);
|
||||
let deleteIndex = this.bucketList.findIndex(
|
||||
(indexBucket) => indexBucket.name === oldBucket.name
|
||||
);
|
||||
|
||||
if (deleteIndex === -1) {
|
||||
console.error("Invalid index for bucket");
|
||||
return;
|
||||
}
|
||||
|
||||
this.bucketList.splice(deleteIndex, 1);
|
||||
});
|
||||
|
||||
// Update tampermonkey bucket index
|
||||
GM_setValue(this.bucketListKey, this.bucketList);
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,3 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export enum LogLevel {
|
||||
TRACE = 10,
|
||||
DEBUG = 20,
|
||||
@ -16,161 +14,17 @@ export enum LogLabel {
|
||||
FATAL = "fatal",
|
||||
}
|
||||
|
||||
export interface TampermonkeyOutputOpts {
|
||||
enabled: boolean;
|
||||
maxBuckets?: number;
|
||||
bucketIndexKey?: string;
|
||||
}
|
||||
|
||||
export interface ConsoleOutputOpts {
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export const ConsoleStyles = z
|
||||
.object({
|
||||
trace: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#949494").optional(),
|
||||
textColor: z.string().default("#fff").optional(),
|
||||
})
|
||||
.default({})
|
||||
.optional(),
|
||||
debug: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#fe7bf3").optional(),
|
||||
textColor: z.string().default("#fff").optional(),
|
||||
})
|
||||
.default({})
|
||||
.optional(),
|
||||
info: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#65f10e").optional(),
|
||||
textColor: z.string().default("#fff").optional(),
|
||||
})
|
||||
.default({})
|
||||
.optional(),
|
||||
warn: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#faf200").optional(),
|
||||
textColor: z.string().default("#000").optional(),
|
||||
})
|
||||
.default({})
|
||||
.optional(),
|
||||
fatal: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#cc0018").optional(),
|
||||
textColor: z.string().default("#fff").optional(),
|
||||
})
|
||||
.default({})
|
||||
.optional(),
|
||||
})
|
||||
.optional();
|
||||
|
||||
export type ConsoleStyles = z.infer<typeof ConsoleStyles>;
|
||||
|
||||
export const StrictConsoleStyles = z
|
||||
.object({
|
||||
trace: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#949494"),
|
||||
textColor: z.string().default("#fff"),
|
||||
})
|
||||
.default({}),
|
||||
debug: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#fe7bf3"),
|
||||
textColor: z.string().default("#fff"),
|
||||
})
|
||||
.default({}),
|
||||
info: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#65f10e"),
|
||||
textColor: z.string().default("#fff"),
|
||||
})
|
||||
.default({}),
|
||||
warn: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#faf200"),
|
||||
textColor: z.string().default("#000"),
|
||||
})
|
||||
.default({}),
|
||||
fatal: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#cc0018"),
|
||||
textColor: z.string().default("#fff"),
|
||||
})
|
||||
.default({}),
|
||||
})
|
||||
.default({});
|
||||
|
||||
export const LogOutputs = z.object({
|
||||
console: z
|
||||
.object({
|
||||
enabled: z.boolean().default(true).optional(),
|
||||
style: ConsoleStyles,
|
||||
})
|
||||
.default({})
|
||||
.optional(),
|
||||
tampermonkey: z
|
||||
.object({
|
||||
enabled: z.boolean().default(false).optional(),
|
||||
maxBuckets: z.number().default(10).optional(),
|
||||
bucketIndexKey: z.string().default("bucket_index").optional(),
|
||||
})
|
||||
.default({})
|
||||
.optional(),
|
||||
callback: z.function().args(z.string()).optional(),
|
||||
});
|
||||
|
||||
export type LogOutputs = z.infer<typeof LogOutputs>;
|
||||
|
||||
export const LogConfig = z.object({
|
||||
outputs: LogOutputs.default({}).optional(),
|
||||
bufferCapacity: z.number().default(100000).optional(),
|
||||
});
|
||||
|
||||
export type LogConfig = z.infer<typeof LogConfig>;
|
||||
|
||||
export const StrictLogOutputs = z.object({
|
||||
console: z
|
||||
.object({
|
||||
enabled: z.boolean().default(true),
|
||||
style: StrictConsoleStyles,
|
||||
})
|
||||
.default({}),
|
||||
tampermonkey: z
|
||||
.object({
|
||||
enabled: z.boolean().default(false),
|
||||
maxBuckets: z.number().default(10),
|
||||
bucketIndexKey: z.string().default("bucket_index"),
|
||||
})
|
||||
.default({}),
|
||||
callback: z.function().args(z.string()).optional(),
|
||||
});
|
||||
|
||||
export type StrictLogOutputs = z.infer<typeof StrictLogOutputs>;
|
||||
|
||||
export const StrictLogConfig = z.object({
|
||||
outputs: StrictLogOutputs.default({}),
|
||||
bufferCapacity: z.number().default(100000),
|
||||
});
|
||||
|
||||
export type StrictLogConfig = z.infer<typeof StrictLogConfig>;
|
||||
|
||||
export interface LogContext {
|
||||
level?: number;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface LogMeta {
|
||||
level: LogLevel;
|
||||
time: Date;
|
||||
}
|
||||
|
||||
export interface LogData {
|
||||
message: string;
|
||||
meta: LogMeta;
|
||||
context: LogContext;
|
||||
time: number;
|
||||
}
|
||||
|
||||
export interface BucketInfo {
|
||||
name: string;
|
||||
size: number;
|
||||
createdAt: number;
|
||||
}
|
||||
|
||||
export type StrictConsoleStyles = z.infer<typeof StrictConsoleStyles>;
|
||||
|
||||
125
src/types/output.ts
Normal file
125
src/types/output.ts
Normal file
@ -0,0 +1,125 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const ConsoleStyles = z
|
||||
.object({
|
||||
trace: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#949494").optional(),
|
||||
textColor: z.string().default("#fff").optional(),
|
||||
})
|
||||
.default({})
|
||||
.optional(),
|
||||
debug: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#fe7bf3").optional(),
|
||||
textColor: z.string().default("#fff").optional(),
|
||||
})
|
||||
.default({})
|
||||
.optional(),
|
||||
info: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#65f10e").optional(),
|
||||
textColor: z.string().default("#fff").optional(),
|
||||
})
|
||||
.default({})
|
||||
.optional(),
|
||||
warn: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#faf200").optional(),
|
||||
textColor: z.string().default("#000").optional(),
|
||||
})
|
||||
.default({})
|
||||
.optional(),
|
||||
fatal: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#cc0018").optional(),
|
||||
textColor: z.string().default("#fff").optional(),
|
||||
})
|
||||
.default({})
|
||||
.optional(),
|
||||
})
|
||||
.optional();
|
||||
|
||||
export type ConsoleStyles = z.infer<typeof ConsoleStyles>;
|
||||
|
||||
export const StrictConsoleStyles = z
|
||||
.object({
|
||||
trace: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#949494"),
|
||||
textColor: z.string().default("#fff"),
|
||||
})
|
||||
.default({}),
|
||||
debug: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#fe7bf3"),
|
||||
textColor: z.string().default("#fff"),
|
||||
})
|
||||
.default({}),
|
||||
info: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#65f10e"),
|
||||
textColor: z.string().default("#fff"),
|
||||
})
|
||||
.default({}),
|
||||
warn: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#faf200"),
|
||||
textColor: z.string().default("#000"),
|
||||
})
|
||||
.default({}),
|
||||
fatal: z
|
||||
.object({
|
||||
backgroundColor: z.string().default("#cc0018"),
|
||||
textColor: z.string().default("#fff"),
|
||||
})
|
||||
.default({}),
|
||||
})
|
||||
.default({});
|
||||
|
||||
export const ConsoleOutputConfig = z.object({
|
||||
enabled: z.boolean().default(true).optional(),
|
||||
style: ConsoleStyles,
|
||||
});
|
||||
|
||||
export type ConsoleOutputConfig = z.infer<typeof ConsoleOutputConfig>;
|
||||
|
||||
export const StrictConsoleOutputConfig = z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
style: StrictConsoleStyles,
|
||||
});
|
||||
|
||||
export type StrictConsoleOutputConfig = z.infer<
|
||||
typeof StrictConsoleOutputConfig
|
||||
>;
|
||||
|
||||
export const TampermonkeyOutputConfig = z
|
||||
.object({
|
||||
enabled: z.boolean().default(false).optional(),
|
||||
maxBuckets: z.number().default(10).optional(),
|
||||
bufferCapacity: z.number().default(10000).optional(),
|
||||
bucketListKey: z.string().default("bucket_index").optional(),
|
||||
})
|
||||
.default({})
|
||||
.optional();
|
||||
|
||||
export type TampermonkeyOutputConfig = z.infer<typeof TampermonkeyOutputConfig>;
|
||||
|
||||
export const StrictTampermonkeyOutputConfig = z
|
||||
.object({
|
||||
enabled: z.boolean().default(true),
|
||||
maxBuckets: z.number().default(10),
|
||||
bufferCapacity: z.number().default(10000),
|
||||
bucketListKey: z.string().default("bucket_index"),
|
||||
})
|
||||
.default({});
|
||||
|
||||
export type StrictTampermonkeyOutputConfig = z.infer<
|
||||
typeof StrictTampermonkeyOutputConfig
|
||||
>;
|
||||
|
||||
export interface TampermonkeyBucketInfo {
|
||||
name: string;
|
||||
size: number;
|
||||
createdAt: number;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user