@vpmedia/simplify 1.73.0 → 1.75.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +67 -0
- package/dist/const/http_status.d.ts +66 -0
- package/dist/const/http_status.d.ts.map +1 -0
- package/dist/const/http_status.js +133 -0
- package/dist/const/http_status.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/{src → dist}/index.js +3 -20
- package/dist/index.js.map +1 -0
- package/dist/logging/AbstractLogHandler.d.ts +17 -0
- package/dist/logging/AbstractLogHandler.d.ts.map +1 -0
- package/dist/logging/AbstractLogHandler.js +16 -0
- package/dist/logging/AbstractLogHandler.js.map +1 -0
- package/dist/logging/ConsoleLogHandler.d.ts +13 -0
- package/dist/logging/ConsoleLogHandler.d.ts.map +1 -0
- package/dist/logging/ConsoleLogHandler.js +41 -0
- package/dist/logging/ConsoleLogHandler.js.map +1 -0
- package/dist/logging/Logger.d.ts +19 -0
- package/dist/logging/Logger.d.ts.map +1 -0
- package/dist/logging/Logger.js +51 -0
- package/dist/logging/Logger.js.map +1 -0
- package/dist/logging/OpenTelemetryLogHandler.d.ts +15 -0
- package/dist/logging/OpenTelemetryLogHandler.d.ts.map +1 -0
- package/dist/logging/OpenTelemetryLogHandler.js +21 -0
- package/dist/logging/OpenTelemetryLogHandler.js.map +1 -0
- package/dist/logging/SentryLogHandler.d.ts +13 -0
- package/dist/logging/SentryLogHandler.d.ts.map +1 -0
- package/dist/logging/SentryLogHandler.js +36 -0
- package/dist/logging/SentryLogHandler.js.map +1 -0
- package/dist/logging/const.d.ts +14 -0
- package/dist/logging/const.d.ts.map +1 -0
- package/dist/logging/const.js +21 -0
- package/dist/logging/const.js.map +1 -0
- package/dist/logging/util.d.ts +14 -0
- package/dist/logging/util.d.ts.map +1 -0
- package/dist/logging/util.js +34 -0
- package/dist/logging/util.js.map +1 -0
- package/dist/pagelifecycle/const.d.ts +15 -0
- package/dist/pagelifecycle/const.d.ts.map +1 -0
- package/dist/pagelifecycle/const.js +27 -0
- package/dist/pagelifecycle/const.js.map +1 -0
- package/dist/pagelifecycle/typedef.d.ts +4 -0
- package/dist/pagelifecycle/typedef.d.ts.map +1 -0
- package/dist/pagelifecycle/typedef.js +2 -0
- package/dist/pagelifecycle/typedef.js.map +1 -0
- package/dist/pagelifecycle/util.d.ts +31 -0
- package/dist/pagelifecycle/util.d.ts.map +1 -0
- package/dist/pagelifecycle/util.js +117 -0
- package/dist/pagelifecycle/util.js.map +1 -0
- package/dist/typecheck/TypeCheckError.d.ts +11 -0
- package/dist/typecheck/TypeCheckError.d.ts.map +1 -0
- package/dist/typecheck/TypeCheckError.js +12 -0
- package/dist/typecheck/TypeCheckError.js.map +1 -0
- package/dist/typecheck/TypeChecker.d.ts +27 -0
- package/dist/typecheck/TypeChecker.d.ts.map +1 -0
- package/dist/typecheck/TypeChecker.js +69 -0
- package/dist/typecheck/TypeChecker.js.map +1 -0
- package/dist/typecheck/util.d.ts +17 -0
- package/dist/typecheck/util.d.ts.map +1 -0
- package/dist/typecheck/util.js +42 -0
- package/dist/typecheck/util.js.map +1 -0
- package/dist/util/async.d.ts +13 -0
- package/dist/util/async.d.ts.map +1 -0
- package/dist/util/async.js +39 -0
- package/dist/util/async.js.map +1 -0
- package/dist/util/error.d.ts +16 -0
- package/dist/util/error.d.ts.map +1 -0
- package/dist/util/error.js +27 -0
- package/dist/util/error.js.map +1 -0
- package/dist/util/event_emitter.d.ts +42 -0
- package/dist/util/event_emitter.d.ts.map +1 -0
- package/dist/util/event_emitter.js +127 -0
- package/dist/util/event_emitter.js.map +1 -0
- package/dist/util/fetch.d.ts +22 -0
- package/dist/util/fetch.d.ts.map +1 -0
- package/dist/util/fetch.js +75 -0
- package/dist/util/fetch.js.map +1 -0
- package/dist/util/number.d.ts +23 -0
- package/dist/util/number.d.ts.map +1 -0
- package/dist/util/number.js +52 -0
- package/dist/util/number.js.map +1 -0
- package/dist/util/object.d.ts +24 -0
- package/dist/util/object.d.ts.map +1 -0
- package/dist/util/object.js +83 -0
- package/dist/util/object.js.map +1 -0
- package/dist/util/query.d.ts +11 -0
- package/dist/util/query.d.ts.map +1 -0
- package/dist/util/query.js +24 -0
- package/dist/util/query.js.map +1 -0
- package/dist/util/state.d.ts +5 -0
- package/dist/util/state.d.ts.map +1 -0
- package/dist/util/state.js +19 -0
- package/dist/util/state.js.map +1 -0
- package/dist/util/string.d.ts +25 -0
- package/dist/util/string.d.ts.map +1 -0
- package/dist/util/string.js +59 -0
- package/dist/util/string.js.map +1 -0
- package/dist/util/uuid.d.ts +13 -0
- package/dist/util/uuid.d.ts.map +1 -0
- package/dist/util/uuid.js +27 -0
- package/dist/util/uuid.js.map +1 -0
- package/dist/util/validate.d.ts +106 -0
- package/dist/util/validate.d.ts.map +1 -0
- package/dist/util/validate.js +139 -0
- package/dist/util/validate.js.map +1 -0
- package/package.json +31 -16
- package/src/const/http_status.test.ts +7 -0
- package/src/const/{http_status.js → http_status.ts} +1 -1
- package/src/index.ts +51 -0
- package/src/logging/AbstractLogHandler.ts +31 -0
- package/src/logging/{ConsoleLogHandler.js → ConsoleLogHandler.ts} +15 -13
- package/src/logging/Logger.test.ts +69 -0
- package/src/logging/Logger.ts +77 -0
- package/src/logging/OpenTelemetryLogHandler.ts +40 -0
- package/src/logging/SentryLogHandler.ts +44 -0
- package/src/logging/{const.js → const.ts} +1 -1
- package/src/logging/util.test.ts +33 -0
- package/src/logging/util.ts +36 -0
- package/src/pagelifecycle/{const.js → const.ts} +2 -2
- package/src/pagelifecycle/typedef.ts +5 -0
- package/src/pagelifecycle/util.test.ts +99 -0
- package/src/pagelifecycle/{util.js → util.ts} +14 -27
- package/src/typecheck/{TypeCheckError.js → TypeCheckError.ts} +7 -3
- package/src/typecheck/TypeChecker.test.ts +70 -0
- package/src/typecheck/{TypeChecker.js → TypeChecker.ts} +10 -27
- package/src/typecheck/util.test.ts +36 -0
- package/src/typecheck/util.ts +50 -0
- package/src/util/async.test.ts +74 -0
- package/src/util/{async.js → async.ts} +3 -11
- package/src/util/error.test.ts +32 -0
- package/src/util/error.ts +37 -0
- package/src/util/event_emitter.test.ts +228 -0
- package/src/util/event_emitter.ts +147 -0
- package/src/util/fetch.test.ts +62 -0
- package/src/util/{fetch.js → fetch.ts} +40 -31
- package/src/util/number.test.ts +124 -0
- package/src/util/number.ts +58 -0
- package/src/util/object.test.ts +203 -0
- package/src/util/{object.js → object.ts} +14 -21
- package/src/util/query.test.ts +71 -0
- package/src/util/query.ts +35 -0
- package/src/util/state.test.ts +47 -0
- package/src/util/{state.js → state.ts} +3 -6
- package/src/util/string.test.ts +64 -0
- package/src/util/string.ts +65 -0
- package/src/util/uuid.test.ts +53 -0
- package/src/util/uuid.ts +31 -0
- package/src/util/validate.test.ts +309 -0
- package/src/util/validate.ts +230 -0
- package/.vscode/extensions.json +0 -6
- package/.vscode/settings.json +0 -27
- package/src/logging/AbstractLogHandler.js +0 -23
- package/src/logging/Logger.js +0 -115
- package/src/logging/OpenTelemetryLogHandler.js +0 -30
- package/src/logging/SentryLogHandler.js +0 -46
- package/src/logging/util.js +0 -41
- package/src/pagelifecycle/typedef.js +0 -9
- package/src/typecheck/util.js +0 -60
- package/src/util/error.js +0 -33
- package/src/util/event_emitter.js +0 -196
- package/src/util/number.js +0 -118
- package/src/util/query.js +0 -32
- package/src/util/string.js +0 -76
- package/src/util/uuid.js +0 -35
- package/src/util/validate.js +0 -247
- package/types/const/http_status.d.ts +0 -131
- package/types/const/http_status.d.ts.map +0 -1
- package/types/index.d.ts +0 -26
- package/types/index.d.ts.map +0 -1
- package/types/logging/AbstractLogHandler.d.ts +0 -20
- package/types/logging/AbstractLogHandler.d.ts.map +0 -1
- package/types/logging/ConsoleLogHandler.d.ts +0 -9
- package/types/logging/ConsoleLogHandler.d.ts.map +0 -1
- package/types/logging/Logger.d.ts +0 -66
- package/types/logging/Logger.d.ts.map +0 -1
- package/types/logging/OpenTelemetryLogHandler.d.ts +0 -11
- package/types/logging/OpenTelemetryLogHandler.d.ts.map +0 -1
- package/types/logging/SentryLogHandler.d.ts +0 -9
- package/types/logging/SentryLogHandler.d.ts.map +0 -1
- package/types/logging/const.d.ts +0 -14
- package/types/logging/const.d.ts.map +0 -1
- package/types/logging/util.d.ts +0 -4
- package/types/logging/util.d.ts.map +0 -1
- package/types/pagelifecycle/const.d.ts +0 -15
- package/types/pagelifecycle/const.d.ts.map +0 -1
- package/types/pagelifecycle/typedef.d.ts +0 -4
- package/types/pagelifecycle/typedef.d.ts.map +0 -1
- package/types/pagelifecycle/util.d.ts +0 -8
- package/types/pagelifecycle/util.d.ts.map +0 -1
- package/types/typecheck/TypeCheckError.d.ts +0 -13
- package/types/typecheck/TypeCheckError.d.ts.map +0 -1
- package/types/typecheck/TypeChecker.d.ts +0 -40
- package/types/typecheck/TypeChecker.d.ts.map +0 -1
- package/types/typecheck/util.d.ts +0 -4
- package/types/typecheck/util.d.ts.map +0 -1
- package/types/util/async.d.ts +0 -4
- package/types/util/async.d.ts.map +0 -1
- package/types/util/error.d.ts +0 -3
- package/types/util/error.d.ts.map +0 -1
- package/types/util/event_emitter.d.ts +0 -69
- package/types/util/event_emitter.d.ts.map +0 -1
- package/types/util/fetch.d.ts +0 -22
- package/types/util/fetch.d.ts.map +0 -1
- package/types/util/number.d.ts +0 -11
- package/types/util/number.d.ts.map +0 -1
- package/types/util/object.d.ts +0 -6
- package/types/util/object.d.ts.map +0 -1
- package/types/util/query.d.ts +0 -3
- package/types/util/query.d.ts.map +0 -1
- package/types/util/state.d.ts +0 -2
- package/types/util/state.d.ts.map +0 -1
- package/types/util/string.d.ts +0 -7
- package/types/util/string.d.ts.map +0 -1
- package/types/util/uuid.d.ts +0 -4
- package/types/util/uuid.d.ts.map +0 -1
- package/types/util/validate.d.ts +0 -45
- package/types/util/validate.d.ts.map +0 -1
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { AbstractLogHandler } from './AbstractLogHandler.js';
|
|
1
|
+
import { AbstractLogHandler, type LogExtra } from './AbstractLogHandler.js';
|
|
2
2
|
import { LOG_LEVEL_DEBUG } from './const.js';
|
|
3
|
+
import type { Logger } from './Logger.js';
|
|
3
4
|
import { formatLogMessage } from './util.js';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
type ConsoleFn = (...data: unknown[]) => void;
|
|
7
|
+
|
|
8
|
+
const CONSOLE_FUNCTIONS: ReadonlyArray<ConsoleFn | null> = [
|
|
6
9
|
null, // silent
|
|
7
10
|
console.error, // fatal
|
|
8
11
|
console.error, // error
|
|
@@ -14,29 +17,28 @@ const CONSOLE_FUNCTIONS = [
|
|
|
14
17
|
export class ConsoleLogHandler extends AbstractLogHandler {
|
|
15
18
|
/**
|
|
16
19
|
* Console log handler.
|
|
17
|
-
* @param {number} level - Log handler level.
|
|
18
20
|
*/
|
|
19
|
-
constructor(level = LOG_LEVEL_DEBUG) {
|
|
21
|
+
constructor(level: number = LOG_LEVEL_DEBUG) {
|
|
20
22
|
super(level);
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
/**
|
|
24
26
|
* Emit log record.
|
|
25
|
-
* @param {import('./Logger.js').Logger} logger - Logger instance.
|
|
26
|
-
* @param {number} timestamp - Log timestamp.
|
|
27
|
-
* @param {number} level - Log level.
|
|
28
|
-
* @param {string} message - Log message.
|
|
29
|
-
* @param {object | null | undefined} extra - Log extra data.
|
|
30
|
-
* @param {Error | null | undefined} error - Log error.
|
|
31
|
-
* @throws {Error}
|
|
32
27
|
*/
|
|
33
|
-
emit(
|
|
28
|
+
override emit(
|
|
29
|
+
logger: Logger,
|
|
30
|
+
timestamp: number,
|
|
31
|
+
level: number,
|
|
32
|
+
message: string,
|
|
33
|
+
extra: LogExtra | null | undefined,
|
|
34
|
+
error: Error | null | undefined
|
|
35
|
+
): void {
|
|
34
36
|
if (logger.level < level) {
|
|
35
37
|
return;
|
|
36
38
|
}
|
|
37
39
|
const logMessage = formatLogMessage(logger, timestamp, level, message);
|
|
38
40
|
const consoleFunction = CONSOLE_FUNCTIONS[level];
|
|
39
|
-
if (consoleFunction === null) {
|
|
41
|
+
if (consoleFunction === null || consoleFunction === undefined) {
|
|
40
42
|
return;
|
|
41
43
|
}
|
|
42
44
|
if (error) {
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { AbstractLogHandler, type LogExtra } from './AbstractLogHandler.js';
|
|
2
|
+
import { LOG_LEVEL_DEBUG, LOG_LEVEL_ERROR, LOG_LEVEL_FATAL, LOG_LEVEL_INFO, LOG_LEVEL_WARNING } from './const.js';
|
|
3
|
+
import { Logger } from './Logger.js';
|
|
4
|
+
|
|
5
|
+
class TestLogHandler extends AbstractLogHandler {
|
|
6
|
+
emitLogLogger: Logger | null = null;
|
|
7
|
+
emitLogTimestamp: number | null = null;
|
|
8
|
+
emitLogLevel: number | null = null;
|
|
9
|
+
emitLogMessage: string | null = null;
|
|
10
|
+
emitLogExtra: LogExtra | null | undefined = null;
|
|
11
|
+
emitLogError: Error | null | undefined = null;
|
|
12
|
+
|
|
13
|
+
constructor() {
|
|
14
|
+
super(LOG_LEVEL_DEBUG);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
override emit(
|
|
18
|
+
logger: Logger,
|
|
19
|
+
timestamp: number,
|
|
20
|
+
level: number,
|
|
21
|
+
message: string,
|
|
22
|
+
extra: LogExtra | null | undefined,
|
|
23
|
+
error: Error | null | undefined
|
|
24
|
+
): void {
|
|
25
|
+
this.emitLogLogger = logger;
|
|
26
|
+
this.emitLogTimestamp = timestamp;
|
|
27
|
+
this.emitLogLevel = level;
|
|
28
|
+
this.emitLogMessage = message;
|
|
29
|
+
this.emitLogExtra = extra;
|
|
30
|
+
this.emitLogError = error;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
test('Tests Logger default level', () => {
|
|
35
|
+
const logger = new Logger('test');
|
|
36
|
+
expect(logger.level).toBe(LOG_LEVEL_DEBUG);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('Tests Logger custom handler', () => {
|
|
40
|
+
const logger = new Logger('test');
|
|
41
|
+
const testLogHandler = new TestLogHandler();
|
|
42
|
+
Logger.addHandler(testLogHandler);
|
|
43
|
+
// debug
|
|
44
|
+
logger.debug('debug');
|
|
45
|
+
expect(testLogHandler.emitLogLevel).toBe(LOG_LEVEL_DEBUG);
|
|
46
|
+
expect(testLogHandler.emitLogMessage).toBe('debug');
|
|
47
|
+
// info
|
|
48
|
+
logger.info('info');
|
|
49
|
+
expect(testLogHandler.emitLogLevel).toBe(LOG_LEVEL_INFO);
|
|
50
|
+
expect(testLogHandler.emitLogMessage).toBe('info');
|
|
51
|
+
// warning
|
|
52
|
+
logger.warn('warning');
|
|
53
|
+
expect(testLogHandler.emitLogLevel).toBe(LOG_LEVEL_WARNING);
|
|
54
|
+
expect(testLogHandler.emitLogMessage).toBe('warning');
|
|
55
|
+
logger.warning('warning');
|
|
56
|
+
expect(testLogHandler.emitLogLevel).toBe(LOG_LEVEL_WARNING);
|
|
57
|
+
expect(testLogHandler.emitLogMessage).toBe('warning');
|
|
58
|
+
// error
|
|
59
|
+
logger.error('error');
|
|
60
|
+
expect(testLogHandler.emitLogLevel).toBe(LOG_LEVEL_ERROR);
|
|
61
|
+
expect(testLogHandler.emitLogMessage).toBe('error');
|
|
62
|
+
// exception
|
|
63
|
+
logger.exception('test', new Error('test_error'), { context: 'ctx' });
|
|
64
|
+
expect(testLogHandler.emitLogLevel).toBe(LOG_LEVEL_FATAL);
|
|
65
|
+
expect(testLogHandler.emitLogMessage).toBe('test');
|
|
66
|
+
expect(testLogHandler.emitLogError?.message).toBe('test_error');
|
|
67
|
+
expect(testLogHandler.emitLogLogger).toBe(logger);
|
|
68
|
+
expect(testLogHandler.emitLogExtra?.['context']).toBe('ctx');
|
|
69
|
+
});
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { getURLParam } from '../util/query.js';
|
|
2
|
+
import type { AbstractLogHandler, LogExtra } from './AbstractLogHandler.js';
|
|
3
|
+
import {
|
|
4
|
+
LOG_LEVEL_DEBUG,
|
|
5
|
+
LOG_LEVEL_ERROR,
|
|
6
|
+
LOG_LEVEL_FATAL,
|
|
7
|
+
LOG_LEVEL_INFO,
|
|
8
|
+
LOG_LEVEL_SILENT,
|
|
9
|
+
LOG_LEVEL_WARNING,
|
|
10
|
+
} from './const.js';
|
|
11
|
+
import { getAppEnvironment } from './util.js';
|
|
12
|
+
|
|
13
|
+
const ROOT_LOGGER_NAME = 'root';
|
|
14
|
+
|
|
15
|
+
export class Logger {
|
|
16
|
+
static handlers: AbstractLogHandler[] = [];
|
|
17
|
+
|
|
18
|
+
name: string;
|
|
19
|
+
level: number;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Creates a new Logger instance.
|
|
23
|
+
*/
|
|
24
|
+
constructor(name: string = ROOT_LOGGER_NAME) {
|
|
25
|
+
this.name = name ?? ROOT_LOGGER_NAME;
|
|
26
|
+
const appEnvironment = getAppEnvironment();
|
|
27
|
+
const isProduction = appEnvironment === 'production' || appEnvironment === 'release';
|
|
28
|
+
const defaultLevel = isProduction ? LOG_LEVEL_SILENT : LOG_LEVEL_DEBUG;
|
|
29
|
+
const parameterName = `log_${this.name.toLowerCase()}`;
|
|
30
|
+
const paramLevel =
|
|
31
|
+
getURLParam(parameterName, getURLParam('log_all', defaultLevel.toString())) ?? defaultLevel.toString();
|
|
32
|
+
this.level = Number.parseInt(paramLevel, 10);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static addHandler = (handler: AbstractLogHandler): void => {
|
|
36
|
+
Logger.handlers.push(handler);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
static emit = (
|
|
40
|
+
logger: Logger,
|
|
41
|
+
level: number,
|
|
42
|
+
message: string,
|
|
43
|
+
extra?: LogExtra | null,
|
|
44
|
+
error?: Error | null
|
|
45
|
+
): void => {
|
|
46
|
+
const timestamp = Date.now();
|
|
47
|
+
for (const handler of Logger.handlers) {
|
|
48
|
+
if (handler.level >= level) {
|
|
49
|
+
handler.emit(logger, timestamp, level, message, extra, error);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
debug(message: string, extra?: LogExtra | null): void {
|
|
55
|
+
Logger.emit(this, LOG_LEVEL_DEBUG, message, extra);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
info(message: string, extra?: LogExtra | null): void {
|
|
59
|
+
Logger.emit(this, LOG_LEVEL_INFO, message, extra);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
warn(message: string, extra?: LogExtra | null): void {
|
|
63
|
+
Logger.emit(this, LOG_LEVEL_WARNING, message, extra);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
warning(message: string, extra?: LogExtra | null): void {
|
|
67
|
+
Logger.emit(this, LOG_LEVEL_WARNING, message, extra);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
error(message: string, extra?: LogExtra | null): void {
|
|
71
|
+
Logger.emit(this, LOG_LEVEL_ERROR, message, extra);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
exception(message: string, error: Error, extra?: LogExtra | null): void {
|
|
75
|
+
Logger.emit(this, LOG_LEVEL_FATAL, message, extra, error);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { AbstractLogHandler, type LogExtra } from './AbstractLogHandler.js';
|
|
2
|
+
import type { Logger } from './Logger.js';
|
|
3
|
+
|
|
4
|
+
export type OpenTelemetryLogEmitter = (
|
|
5
|
+
logger: Logger,
|
|
6
|
+
timestamp: number,
|
|
7
|
+
level: number,
|
|
8
|
+
message: string,
|
|
9
|
+
extra: LogExtra | null | undefined,
|
|
10
|
+
error: Error | null | undefined
|
|
11
|
+
) => void;
|
|
12
|
+
|
|
13
|
+
export class OpenTelemetryLogHandler extends AbstractLogHandler {
|
|
14
|
+
emitter: OpenTelemetryLogEmitter;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Open Telemetry log handler.
|
|
18
|
+
*/
|
|
19
|
+
constructor(level: number, emitter: OpenTelemetryLogEmitter) {
|
|
20
|
+
super(level);
|
|
21
|
+
this.emitter = emitter;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Emit log record.
|
|
26
|
+
*/
|
|
27
|
+
override emit(
|
|
28
|
+
logger: Logger,
|
|
29
|
+
timestamp: number,
|
|
30
|
+
level: number,
|
|
31
|
+
message: string,
|
|
32
|
+
extra: LogExtra | null | undefined,
|
|
33
|
+
error: Error | null | undefined
|
|
34
|
+
): void {
|
|
35
|
+
if (!this.emitter) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
this.emitter(logger, timestamp, level, message, extra, error);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { addBreadcrumb, captureException, captureMessage, type SeverityLevel } from '@sentry/browser';
|
|
2
|
+
import { AbstractLogHandler, type LogExtra } from './AbstractLogHandler.js';
|
|
3
|
+
import { LOG_LEVEL_DEBUG, LOG_LEVEL_WARNING } from './const.js';
|
|
4
|
+
import type { Logger } from './Logger.js';
|
|
5
|
+
import { getLogLevelName } from './util.js';
|
|
6
|
+
|
|
7
|
+
export class SentryLogHandler extends AbstractLogHandler {
|
|
8
|
+
/**
|
|
9
|
+
* Sentry log handler.
|
|
10
|
+
*/
|
|
11
|
+
constructor(level: number = LOG_LEVEL_DEBUG) {
|
|
12
|
+
super(level);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Emit log record.
|
|
17
|
+
*/
|
|
18
|
+
override emit(
|
|
19
|
+
logger: Logger,
|
|
20
|
+
_timestamp: number,
|
|
21
|
+
level: number,
|
|
22
|
+
message: string,
|
|
23
|
+
extra: LogExtra | null | undefined,
|
|
24
|
+
error: Error | null | undefined
|
|
25
|
+
): void {
|
|
26
|
+
const levelName = getLogLevelName(level) as SeverityLevel;
|
|
27
|
+
const logMessage = `[${logger.name}] ${message}`;
|
|
28
|
+
const breadcrumb = {
|
|
29
|
+
type: 'default',
|
|
30
|
+
category: 'console',
|
|
31
|
+
message: logMessage,
|
|
32
|
+
level: levelName,
|
|
33
|
+
data: extra ?? undefined,
|
|
34
|
+
};
|
|
35
|
+
addBreadcrumb(breadcrumb);
|
|
36
|
+
if (error) {
|
|
37
|
+
extra?.tags ? captureException(error, { tags: extra.tags }) : captureException(error);
|
|
38
|
+
} else if (level === LOG_LEVEL_WARNING) {
|
|
39
|
+
extra?.tags
|
|
40
|
+
? captureMessage(logMessage, { level: 'warning', tags: extra.tags })
|
|
41
|
+
: captureMessage(logMessage, { level: 'warning' });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -12,7 +12,7 @@ export const LOG_LEVEL_NAME_WARNING = 'warning';
|
|
|
12
12
|
export const LOG_LEVEL_NAME_INFO = 'info';
|
|
13
13
|
export const LOG_LEVEL_NAME_DEBUG = 'debug';
|
|
14
14
|
|
|
15
|
-
export const LOG_LEVEL_NAMES = [
|
|
15
|
+
export const LOG_LEVEL_NAMES: readonly string[] = [
|
|
16
16
|
LOG_LEVEL_NAME_SILENT,
|
|
17
17
|
LOG_LEVEL_NAME_FATAL,
|
|
18
18
|
LOG_LEVEL_NAME_ERROR,
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LOG_LEVEL_DEBUG,
|
|
3
|
+
LOG_LEVEL_ERROR,
|
|
4
|
+
LOG_LEVEL_FATAL,
|
|
5
|
+
LOG_LEVEL_INFO,
|
|
6
|
+
LOG_LEVEL_NAME_DEBUG,
|
|
7
|
+
LOG_LEVEL_NAME_ERROR,
|
|
8
|
+
LOG_LEVEL_NAME_FATAL,
|
|
9
|
+
LOG_LEVEL_NAME_INFO,
|
|
10
|
+
LOG_LEVEL_NAME_SILENT,
|
|
11
|
+
LOG_LEVEL_NAME_WARNING,
|
|
12
|
+
LOG_LEVEL_SILENT,
|
|
13
|
+
LOG_LEVEL_WARNING,
|
|
14
|
+
} from './const.js';
|
|
15
|
+
import { Logger } from './Logger.js';
|
|
16
|
+
import { formatLogMessage, getLogLevelName } from './util.js';
|
|
17
|
+
|
|
18
|
+
test('formatLogMessage()', () => {
|
|
19
|
+
expect(
|
|
20
|
+
formatLogMessage(new Logger('loggerName'), Date.now(), LOG_LEVEL_INFO, 'logMessage').endsWith(
|
|
21
|
+
'[loggerName] logMessage'
|
|
22
|
+
)
|
|
23
|
+
).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('getLogLevelName()', () => {
|
|
27
|
+
expect(getLogLevelName(LOG_LEVEL_DEBUG)).toBe(LOG_LEVEL_NAME_DEBUG);
|
|
28
|
+
expect(getLogLevelName(LOG_LEVEL_INFO)).toBe(LOG_LEVEL_NAME_INFO);
|
|
29
|
+
expect(getLogLevelName(LOG_LEVEL_WARNING)).toBe(LOG_LEVEL_NAME_WARNING);
|
|
30
|
+
expect(getLogLevelName(LOG_LEVEL_ERROR)).toBe(LOG_LEVEL_NAME_ERROR);
|
|
31
|
+
expect(getLogLevelName(LOG_LEVEL_FATAL)).toBe(LOG_LEVEL_NAME_FATAL);
|
|
32
|
+
expect(getLogLevelName(LOG_LEVEL_SILENT)).toBe(LOG_LEVEL_NAME_SILENT);
|
|
33
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Logger } from './Logger.js';
|
|
2
|
+
import { LOG_LEVEL_NAMES } from './const.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Format log message.
|
|
6
|
+
*/
|
|
7
|
+
export const formatLogMessage = (logger: Logger, timestamp: number, _level: number, message: string): string =>
|
|
8
|
+
`${timestamp} [${logger.name}] ${message}`;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Get log level name.
|
|
12
|
+
*/
|
|
13
|
+
export const getLogLevelName = (level: number): string | undefined => LOG_LEVEL_NAMES[level];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Returns the application environment identifier.
|
|
17
|
+
*/
|
|
18
|
+
export const getAppEnvironment = (): string => {
|
|
19
|
+
let appEnvironment = 'local';
|
|
20
|
+
try {
|
|
21
|
+
const { env } = import.meta as unknown as { env?: Record<string, string | undefined> };
|
|
22
|
+
if (env?.['VITE_APP_ENVIRONMENT']) {
|
|
23
|
+
appEnvironment = env['VITE_APP_ENVIRONMENT'];
|
|
24
|
+
}
|
|
25
|
+
} catch {
|
|
26
|
+
// pass
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
if (process.env['APP_ENVIRONMENT']) {
|
|
30
|
+
appEnvironment = process.env['APP_ENVIRONMENT'];
|
|
31
|
+
}
|
|
32
|
+
} catch {
|
|
33
|
+
// pass
|
|
34
|
+
}
|
|
35
|
+
return appEnvironment;
|
|
36
|
+
};
|
|
@@ -4,7 +4,7 @@ export const PAGE_LIFECYCLE_STATE_PASSIVE = 'passive';
|
|
|
4
4
|
export const PAGE_LIFECYCLE_STATE_FROZEN = 'frozen';
|
|
5
5
|
export const PAGE_LIFECYCLE_STATE_TERMINATED = 'terminated';
|
|
6
6
|
|
|
7
|
-
export const PAGE_LIFECYCLE_STATES = new Set([
|
|
7
|
+
export const PAGE_LIFECYCLE_STATES: ReadonlySet<string> = new Set([
|
|
8
8
|
PAGE_LIFECYCLE_STATE_ACTIVE,
|
|
9
9
|
PAGE_LIFECYCLE_STATE_FROZEN,
|
|
10
10
|
PAGE_LIFECYCLE_STATE_HIDDEN,
|
|
@@ -18,7 +18,7 @@ export const DOCUMENT_STATE_COMPLETE = 'complete';
|
|
|
18
18
|
export const DOCUMENT_STATE_INTERACTIVE = 'interactive';
|
|
19
19
|
export const DOCUMENT_STATE_LOADING = 'loading';
|
|
20
20
|
|
|
21
|
-
export const DOCUMENT_STATES = new Set([
|
|
21
|
+
export const DOCUMENT_STATES: ReadonlySet<string> = new Set([
|
|
22
22
|
DOCUMENT_STATE_COMPLETE,
|
|
23
23
|
DOCUMENT_STATE_DOM_LOADED,
|
|
24
24
|
DOCUMENT_STATE_FULLY_LOADED,
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { beforeAll, describe, expect, it } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
DOCUMENT_STATE_CHANGE_EVENT,
|
|
4
|
+
DOCUMENT_STATES,
|
|
5
|
+
PAGE_LIFECYCLE_STATE_CHANGE_EVENT,
|
|
6
|
+
PAGE_LIFECYCLE_STATES,
|
|
7
|
+
} from './const.js';
|
|
8
|
+
import {
|
|
9
|
+
getDocumentState,
|
|
10
|
+
getPageLifecycleEventEmitter,
|
|
11
|
+
getPageLifecycleState,
|
|
12
|
+
initPageLifecycle,
|
|
13
|
+
isPageLifecycleInitialized,
|
|
14
|
+
} from './util.js';
|
|
15
|
+
|
|
16
|
+
describe('Page Lifecycle', () => {
|
|
17
|
+
beforeAll(() => {
|
|
18
|
+
initPageLifecycle();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should initialize page lifecycle', () => {
|
|
22
|
+
expect(isPageLifecycleInitialized()).toBe(true);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should return current page lifecycle state', () => {
|
|
26
|
+
const state = getPageLifecycleState();
|
|
27
|
+
expect(state).toBeOneOf([...PAGE_LIFECYCLE_STATES]);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should return current document state', () => {
|
|
31
|
+
const state = getDocumentState();
|
|
32
|
+
expect(state).toBeOneOf([...DOCUMENT_STATES]);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should return event emitter instance', () => {
|
|
36
|
+
const emitter = getPageLifecycleEventEmitter();
|
|
37
|
+
expect(emitter).toBeDefined();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should handle page lifecycle state changes', () => {
|
|
41
|
+
const emitter = getPageLifecycleEventEmitter();
|
|
42
|
+
let stateChanged = false;
|
|
43
|
+
|
|
44
|
+
emitter.on(PAGE_LIFECYCLE_STATE_CHANGE_EVENT, (data: unknown) => {
|
|
45
|
+
stateChanged = true;
|
|
46
|
+
expect(data).toHaveProperty('previousState');
|
|
47
|
+
expect(data).toHaveProperty('nextState');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Trigger visibility change
|
|
51
|
+
const originalVisibilityState = document.visibilityState;
|
|
52
|
+
Object.defineProperty(document, 'visibilityState', {
|
|
53
|
+
value: originalVisibilityState === 'visible' ? 'hidden' : 'visible',
|
|
54
|
+
writable: true,
|
|
55
|
+
configurable: true,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
document.dispatchEvent(new Event('visibilitychange'));
|
|
59
|
+
|
|
60
|
+
// Restore original state
|
|
61
|
+
Object.defineProperty(document, 'visibilityState', {
|
|
62
|
+
value: originalVisibilityState,
|
|
63
|
+
writable: true,
|
|
64
|
+
configurable: true,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
expect(stateChanged).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should handle document state changes', () => {
|
|
71
|
+
const emitter = getPageLifecycleEventEmitter();
|
|
72
|
+
let stateChanged = false;
|
|
73
|
+
|
|
74
|
+
emitter.on(DOCUMENT_STATE_CHANGE_EVENT, (data: unknown) => {
|
|
75
|
+
stateChanged = true;
|
|
76
|
+
expect(data).toHaveProperty('previousState');
|
|
77
|
+
expect(data).toHaveProperty('nextState');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Trigger ready state change
|
|
81
|
+
const originalReadyState = document.readyState;
|
|
82
|
+
Object.defineProperty(document, 'readyState', {
|
|
83
|
+
value: originalReadyState === 'complete' ? 'interactive' : 'complete',
|
|
84
|
+
writable: true,
|
|
85
|
+
configurable: true,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
document.dispatchEvent(new Event('readystatechange'));
|
|
89
|
+
|
|
90
|
+
// Restore original state
|
|
91
|
+
Object.defineProperty(document, 'readyState', {
|
|
92
|
+
value: originalReadyState,
|
|
93
|
+
writable: true,
|
|
94
|
+
configurable: true,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
expect(stateChanged).toBe(true);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -16,27 +16,24 @@ import {
|
|
|
16
16
|
PAGE_LIFECYCLE_STATE_PASSIVE,
|
|
17
17
|
PAGE_LIFECYCLE_STATE_TERMINATED,
|
|
18
18
|
} from './const.js';
|
|
19
|
+
import type { DocumentState, PageLifecycleState } from './typedef.js';
|
|
19
20
|
|
|
20
21
|
const logger = new Logger('pagelifecycle');
|
|
21
22
|
|
|
22
23
|
const eventEmitter = new EventEmitter();
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
let currentPageLifecycleState = null;
|
|
25
|
+
let currentPageLifecycleState: PageLifecycleState | null | undefined = null;
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
let currentDocumentState = null;
|
|
27
|
+
let currentDocumentState: DocumentState | null | undefined = null;
|
|
29
28
|
|
|
30
29
|
let isInitialized = false;
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
const callbacks = {};
|
|
31
|
+
const callbacks: Record<string, (() => void)[]> = {};
|
|
34
32
|
|
|
35
33
|
/**
|
|
36
34
|
* Run callbacks for a specific state change.
|
|
37
|
-
* @param {import('./typedef.js').DocumentState | import('./typedef.js').PageLifecycleState} state - Callback state condition.
|
|
38
35
|
*/
|
|
39
|
-
const processCallbacks = (state) => {
|
|
36
|
+
const processCallbacks = (state: DocumentState | PageLifecycleState): void => {
|
|
40
37
|
const stateCallbacks = callbacks[state];
|
|
41
38
|
if (!stateCallbacks) {
|
|
42
39
|
return;
|
|
@@ -49,9 +46,8 @@ const processCallbacks = (state) => {
|
|
|
49
46
|
|
|
50
47
|
/**
|
|
51
48
|
* Detects the current page lifecycle state.
|
|
52
|
-
* @returns {import('./typedef.js').PageLifecycleState} Current page lifecycle state.
|
|
53
49
|
*/
|
|
54
|
-
const detectPageLifecycleState = () => {
|
|
50
|
+
const detectPageLifecycleState = (): PageLifecycleState => {
|
|
55
51
|
if (document.visibilityState === 'hidden') {
|
|
56
52
|
return PAGE_LIFECYCLE_STATE_HIDDEN;
|
|
57
53
|
}
|
|
@@ -63,9 +59,8 @@ const detectPageLifecycleState = () => {
|
|
|
63
59
|
|
|
64
60
|
/**
|
|
65
61
|
* Handles page lifecycle state change.
|
|
66
|
-
* @param {import('./typedef.js').PageLifecycleState} nextState - Next page lifecycle state.
|
|
67
62
|
*/
|
|
68
|
-
const onPageLifecycleStateChange = (nextState) => {
|
|
63
|
+
const onPageLifecycleStateChange = (nextState: PageLifecycleState): void => {
|
|
69
64
|
const previousState = currentPageLifecycleState;
|
|
70
65
|
if (nextState !== previousState) {
|
|
71
66
|
currentPageLifecycleState = nextState;
|
|
@@ -78,9 +73,8 @@ const onPageLifecycleStateChange = (nextState) => {
|
|
|
78
73
|
|
|
79
74
|
/**
|
|
80
75
|
* Handles document state change.
|
|
81
|
-
* @param {import('./typedef.js').DocumentState} nextState - Next document state.
|
|
82
76
|
*/
|
|
83
|
-
const onDocumentStateChange = (nextState) => {
|
|
77
|
+
const onDocumentStateChange = (nextState: DocumentState): void => {
|
|
84
78
|
const previousState = currentDocumentState;
|
|
85
79
|
if (nextState !== previousState) {
|
|
86
80
|
currentDocumentState = nextState;
|
|
@@ -94,7 +88,7 @@ const onDocumentStateChange = (nextState) => {
|
|
|
94
88
|
/**
|
|
95
89
|
* Initialize page lifecycle observer.
|
|
96
90
|
*/
|
|
97
|
-
export const initPageLifecycle = () => {
|
|
91
|
+
export const initPageLifecycle = (): void => {
|
|
98
92
|
if (isInitialized) {
|
|
99
93
|
return;
|
|
100
94
|
}
|
|
@@ -103,7 +97,6 @@ export const initPageLifecycle = () => {
|
|
|
103
97
|
onDocumentStateChange(document.readyState);
|
|
104
98
|
const options = { capture: true };
|
|
105
99
|
document.addEventListener('visibilitychange', () => onPageLifecycleStateChange(detectPageLifecycleState()), options);
|
|
106
|
-
// globalThis.addEventListener('popstate', () => onPageLifecycleStateChange(detectPageLifecycleState()), options);
|
|
107
100
|
globalThis.addEventListener('pageshow', () => onPageLifecycleStateChange(detectPageLifecycleState()), options);
|
|
108
101
|
globalThis.addEventListener('focus', () => onPageLifecycleStateChange(detectPageLifecycleState()), options);
|
|
109
102
|
globalThis.addEventListener('blur', () => onPageLifecycleStateChange(detectPageLifecycleState()), options);
|
|
@@ -123,21 +116,18 @@ export const initPageLifecycle = () => {
|
|
|
123
116
|
|
|
124
117
|
/**
|
|
125
118
|
* Returns the current page lifecycle state.
|
|
126
|
-
* @returns {string | null | undefined} Current page lifecycle state.
|
|
127
119
|
*/
|
|
128
|
-
export const getPageLifecycleState = () => currentPageLifecycleState;
|
|
120
|
+
export const getPageLifecycleState = (): PageLifecycleState | null | undefined => currentPageLifecycleState;
|
|
129
121
|
|
|
130
122
|
/**
|
|
131
123
|
* Returns the current document state.
|
|
132
|
-
* @returns {import('./typedef.js').DocumentState | null | undefined} Current document state.
|
|
133
124
|
*/
|
|
134
|
-
export const getDocumentState = () => currentDocumentState;
|
|
125
|
+
export const getDocumentState = (): DocumentState | null | undefined => currentDocumentState;
|
|
135
126
|
|
|
136
127
|
/**
|
|
137
128
|
* Returns the event emitter instance.
|
|
138
|
-
* @returns {EventEmitter} Event emitter instance.
|
|
139
129
|
*/
|
|
140
|
-
export const getPageLifecycleEventEmitter = () => {
|
|
130
|
+
export const getPageLifecycleEventEmitter = (): EventEmitter => {
|
|
141
131
|
if (!isInitialized) {
|
|
142
132
|
initPageLifecycle();
|
|
143
133
|
}
|
|
@@ -146,16 +136,13 @@ export const getPageLifecycleEventEmitter = () => {
|
|
|
146
136
|
|
|
147
137
|
/**
|
|
148
138
|
* Returns the page lifecycle observer initialized state.
|
|
149
|
-
* @returns {boolean} Page lifecycle observer initialized flag.
|
|
150
139
|
*/
|
|
151
|
-
export const isPageLifecycleInitialized = () => isInitialized;
|
|
140
|
+
export const isPageLifecycleInitialized = (): boolean => isInitialized;
|
|
152
141
|
|
|
153
142
|
/**
|
|
154
143
|
* Add callback for a specific state change.
|
|
155
|
-
* @param {import('./typedef.js').DocumentState | import('./typedef.js').PageLifecycleState} state - Callback state condition.
|
|
156
|
-
* @param {() => void} callback - Callback function.
|
|
157
144
|
*/
|
|
158
|
-
export const addPageLifecycleCallback = (state, callback) => {
|
|
145
|
+
export const addPageLifecycleCallback = (state: DocumentState | PageLifecycleState, callback: () => void): void => {
|
|
159
146
|
const stateCallbacks = callbacks[state] ?? [];
|
|
160
147
|
stateCallbacks.push(callback);
|
|
161
148
|
callbacks[state] = stateCallbacks;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
export interface TypeCheckErrorOptions extends ErrorOptions {
|
|
2
|
+
value?: unknown;
|
|
3
|
+
}
|
|
4
|
+
|
|
1
5
|
export class TypeCheckError extends TypeError {
|
|
6
|
+
value: unknown;
|
|
7
|
+
|
|
2
8
|
/**
|
|
3
9
|
* Creates a new `TypeCheckError` instance.
|
|
4
|
-
* @param {string} message - Error message.
|
|
5
|
-
* @param {{ cause?: unknown, value?: unknown }} [options] - Error options.
|
|
6
10
|
*/
|
|
7
|
-
constructor(message, options) {
|
|
11
|
+
constructor(message: string, options?: TypeCheckErrorOptions) {
|
|
8
12
|
super(message, options);
|
|
9
13
|
this.name = 'TypeCheckError';
|
|
10
14
|
this.value = options?.value;
|