@expressots/core 4.0.0-preview.1 → 4.0.0-preview.3
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/LICENSE.md +21 -21
- package/README.md +66 -66
- package/lib/CHANGELOG.md +774 -774
- package/lib/README.md +66 -66
- package/lib/cjs/application/application-factory.js +6 -0
- package/lib/cjs/application/bootstrap.js +117 -213
- package/lib/cjs/config/define-config.js +1 -1
- package/lib/cjs/config/env-field-builders.js +47 -0
- package/lib/cjs/config/index.js +7 -1
- package/lib/cjs/framework-version.js +10 -0
- package/lib/cjs/lazy-loading/index.js +5 -1
- package/lib/cjs/lazy-loading/lazy-module-helpers.js +49 -0
- package/lib/cjs/middleware/index.js +8 -9
- package/lib/cjs/middleware/middleware-service.js +68 -12
- package/lib/cjs/middleware/presets-standalone.js +93 -0
- package/lib/cjs/provider/db-in-memory/adapter/in-memory.adapter.js +23 -0
- package/lib/cjs/provider/db-in-memory/index.js +11 -1
- package/lib/cjs/provider/db-in-memory/query/query-engine.js +28 -0
- package/lib/cjs/provider/db-in-memory/schema/decorators.js +18 -0
- package/lib/cjs/provider/db-in-memory/storage/index.js +3 -1
- package/lib/cjs/provider/db-in-memory/storage/memory-store.js +72 -1
- package/lib/cjs/provider/logger/logger.banner.js +40 -31
- package/lib/cjs/provider/logger/logger.config.js +11 -1
- package/lib/cjs/provider/logger/logger.formatter.js +22 -1
- package/lib/cjs/provider/logger/logger.provider.js +59 -9
- package/lib/cjs/provider/logger/transports/console.transport.js +69 -6
- package/lib/cjs/provider/logger/transports/file.transport.js +27 -18
- package/lib/cjs/provider/logger/utils/log-levels.js +6 -5
- package/lib/cjs/provider/validation/adapters/index.js +12 -5
- package/lib/cjs/provider/validation/adapters/yup.adapter.js +118 -0
- package/lib/cjs/provider/validation/adapters/zod.adapter.js +137 -0
- package/lib/cjs/provider/validation/index.js +5 -1
- package/lib/cjs/render/adapters/react-adapter.js +14 -14
- package/lib/cjs/render/features/type-generator.js +30 -30
- package/lib/cjs/render/features/view-debugger.js +75 -55
- package/lib/cjs/testing/fluent-request.js +7 -0
- package/lib/cjs/testing/snapshot-request.js +2 -0
- package/lib/cjs/types/application/application-factory.d.ts +6 -0
- package/lib/cjs/types/application/bootstrap.d.ts +196 -24
- package/lib/cjs/types/config/config.interfaces.d.ts +7 -1
- package/lib/cjs/types/config/env-field-builders.d.ts +39 -0
- package/lib/cjs/types/config/index.d.ts +1 -1
- package/lib/cjs/types/framework-version.d.ts +7 -0
- package/lib/cjs/types/lazy-loading/index.d.ts +1 -0
- package/lib/cjs/types/lazy-loading/lazy-module-helpers.d.ts +42 -0
- package/lib/cjs/types/middleware/index.d.ts +1 -1
- package/lib/cjs/types/middleware/middleware-service.d.ts +21 -0
- package/lib/cjs/types/middleware/presets-standalone.d.ts +75 -0
- package/lib/cjs/types/provider/db-in-memory/adapter/in-memory.adapter.d.ts +2 -0
- package/lib/cjs/types/provider/db-in-memory/index.d.ts +9 -1
- package/lib/cjs/types/provider/db-in-memory/query/query-engine.d.ts +14 -1
- package/lib/cjs/types/provider/db-in-memory/schema/decorators.d.ts +14 -0
- package/lib/cjs/types/provider/db-in-memory/storage/index.d.ts +1 -1
- package/lib/cjs/types/provider/db-in-memory/storage/memory-store.d.ts +34 -0
- package/lib/cjs/types/provider/logger/logger.banner.d.ts +1 -1
- package/lib/cjs/types/provider/logger/logger.config.d.ts +7 -0
- package/lib/cjs/types/provider/logger/logger.formatter.d.ts +10 -0
- package/lib/cjs/types/provider/logger/logger.provider.d.ts +32 -1
- package/lib/cjs/types/provider/logger/transports/console.transport.d.ts +7 -0
- package/lib/cjs/types/provider/logger/utils/log-levels.d.ts +3 -3
- package/lib/cjs/types/provider/validation/adapters/index.d.ts +7 -4
- package/lib/cjs/types/provider/validation/adapters/yup.adapter.d.ts +65 -0
- package/lib/cjs/types/provider/validation/adapters/zod.adapter.d.ts +84 -0
- package/lib/cjs/types/provider/validation/index.d.ts +1 -1
- package/lib/cjs/types/render/features/view-debugger.d.ts +10 -0
- package/lib/cjs/types/testing/testing.interfaces.d.ts +31 -6
- package/lib/esm/application/application-factory.js +6 -0
- package/lib/esm/application/bootstrap.js +117 -213
- package/lib/esm/config/define-config.js +1 -1
- package/lib/esm/config/env-field-builders.js +48 -0
- package/lib/esm/config/index.js +6 -1
- package/lib/esm/framework-version.js +7 -0
- package/lib/esm/lazy-loading/index.js +2 -0
- package/lib/esm/lazy-loading/lazy-module-helpers.js +45 -0
- package/lib/esm/middleware/index.js +3 -2
- package/lib/esm/middleware/middleware-service.js +68 -12
- package/lib/esm/middleware/presets-standalone.js +87 -0
- package/lib/esm/provider/db-in-memory/adapter/in-memory.adapter.js +23 -0
- package/lib/esm/provider/db-in-memory/index.js +9 -1
- package/lib/esm/provider/db-in-memory/query/query-engine.js +28 -0
- package/lib/esm/provider/db-in-memory/schema/decorators.js +18 -0
- package/lib/esm/provider/db-in-memory/storage/index.js +1 -1
- package/lib/esm/provider/db-in-memory/storage/memory-store.js +75 -0
- package/lib/esm/provider/logger/logger.banner.js +40 -31
- package/lib/esm/provider/logger/logger.config.js +12 -2
- package/lib/esm/provider/logger/logger.formatter.js +22 -1
- package/lib/esm/provider/logger/logger.provider.js +61 -10
- package/lib/esm/provider/logger/transports/console.transport.js +69 -6
- package/lib/esm/provider/logger/transports/file.transport.js +27 -18
- package/lib/esm/provider/logger/utils/log-levels.js +6 -5
- package/lib/esm/provider/validation/adapters/index.js +7 -4
- package/lib/esm/provider/validation/adapters/yup.adapter.js +111 -0
- package/lib/esm/provider/validation/adapters/zod.adapter.js +130 -0
- package/lib/esm/provider/validation/index.js +1 -1
- package/lib/esm/render/adapters/react-adapter.js +14 -14
- package/lib/esm/render/features/type-generator.js +30 -30
- package/lib/esm/render/features/view-debugger.js +75 -55
- package/lib/esm/testing/fluent-request.js +7 -0
- package/lib/esm/testing/snapshot-request.js +2 -0
- package/lib/esm/types/application/application-factory.d.ts +6 -0
- package/lib/esm/types/application/bootstrap.d.ts +196 -24
- package/lib/esm/types/config/config.interfaces.d.ts +7 -1
- package/lib/esm/types/config/env-field-builders.d.ts +39 -0
- package/lib/esm/types/config/index.d.ts +1 -1
- package/lib/esm/types/framework-version.d.ts +7 -0
- package/lib/esm/types/lazy-loading/index.d.ts +1 -0
- package/lib/esm/types/lazy-loading/lazy-module-helpers.d.ts +42 -0
- package/lib/esm/types/middleware/index.d.ts +1 -1
- package/lib/esm/types/middleware/middleware-service.d.ts +21 -0
- package/lib/esm/types/middleware/presets-standalone.d.ts +75 -0
- package/lib/esm/types/provider/db-in-memory/adapter/in-memory.adapter.d.ts +2 -0
- package/lib/esm/types/provider/db-in-memory/index.d.ts +9 -1
- package/lib/esm/types/provider/db-in-memory/query/query-engine.d.ts +14 -1
- package/lib/esm/types/provider/db-in-memory/schema/decorators.d.ts +14 -0
- package/lib/esm/types/provider/db-in-memory/storage/index.d.ts +1 -1
- package/lib/esm/types/provider/db-in-memory/storage/memory-store.d.ts +34 -0
- package/lib/esm/types/provider/logger/logger.banner.d.ts +1 -1
- package/lib/esm/types/provider/logger/logger.config.d.ts +7 -0
- package/lib/esm/types/provider/logger/logger.formatter.d.ts +10 -0
- package/lib/esm/types/provider/logger/logger.provider.d.ts +32 -1
- package/lib/esm/types/provider/logger/transports/console.transport.d.ts +7 -0
- package/lib/esm/types/provider/logger/utils/log-levels.d.ts +3 -3
- package/lib/esm/types/provider/validation/adapters/index.d.ts +7 -4
- package/lib/esm/types/provider/validation/adapters/yup.adapter.d.ts +65 -0
- package/lib/esm/types/provider/validation/adapters/zod.adapter.d.ts +84 -0
- package/lib/esm/types/provider/validation/index.d.ts +1 -1
- package/lib/esm/types/render/features/view-debugger.d.ts +10 -0
- package/lib/esm/types/testing/testing.interfaces.d.ts +31 -6
- package/lib/package.json +23 -8
- package/package.json +23 -8
- package/lib/cjs/middleware/middleware-presets.js +0 -294
- package/lib/cjs/types/middleware/middleware-presets.d.ts +0 -90
- package/lib/esm/middleware/middleware-presets.js +0 -286
- package/lib/esm/types/middleware/middleware-presets.d.ts +0 -90
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.BannerGenerator = void 0;
|
|
4
4
|
const color_codes_js_1 = require("../../console/color-codes.js");
|
|
5
5
|
const logger_metrics_js_1 = require("./logger.metrics.js");
|
|
6
|
+
const framework_version_js_1 = require("../../framework-version.js");
|
|
6
7
|
// eslint-disable-next-line no-control-regex
|
|
7
8
|
const ANSI_STRIP_REGEX = /\x1b\[[0-9;]*m/g;
|
|
8
9
|
// Helper to write to stdout - uses process.stdout directly to allow runtime interception
|
|
@@ -56,22 +57,41 @@ function getExpressoTSLogo() {
|
|
|
56
57
|
const ts = normalizedTs[i];
|
|
57
58
|
return `║${padLeft}${green}${exp}${reset}${white}${ts}${reset}${padRight}║`;
|
|
58
59
|
});
|
|
59
|
-
return `
|
|
60
|
-
${topBorder}
|
|
61
|
-
${emptyLine}
|
|
62
|
-
${contentLines.join("\n")}
|
|
63
|
-
${emptyLine}
|
|
64
|
-
${bottomBorder}
|
|
60
|
+
return `
|
|
61
|
+
${topBorder}
|
|
62
|
+
${emptyLine}
|
|
63
|
+
${contentLines.join("\n")}
|
|
64
|
+
${emptyLine}
|
|
65
|
+
${bottomBorder}
|
|
65
66
|
`.trim();
|
|
66
67
|
}
|
|
67
68
|
/**
|
|
68
|
-
*
|
|
69
|
+
* Format a timestamp for structured log output.
|
|
69
70
|
*/
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
function formatBannerTimestamp() {
|
|
72
|
+
const options = {
|
|
73
|
+
year: "numeric",
|
|
74
|
+
month: "2-digit",
|
|
75
|
+
day: "2-digit",
|
|
76
|
+
hour: "2-digit",
|
|
77
|
+
minute: "2-digit",
|
|
78
|
+
second: "2-digit",
|
|
79
|
+
};
|
|
80
|
+
return new Date().toLocaleString(undefined, options).replace(",", "");
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Build a structured log line matching the standard ExpressoTS log format.
|
|
84
|
+
*/
|
|
85
|
+
function logLine(message) {
|
|
86
|
+
const timestamp = formatBannerTimestamp();
|
|
87
|
+
const pid = process.pid;
|
|
88
|
+
return (colorText("[ExpressoTS]", "green") +
|
|
89
|
+
` ${timestamp}` +
|
|
90
|
+
` ${colorText(`[PID:${pid}]`, "green")}` +
|
|
91
|
+
` ${colorText("INFO ", "green")}` +
|
|
92
|
+
` ${colorText("[app]", "green")}` +
|
|
93
|
+
` ${message}\n`);
|
|
94
|
+
}
|
|
75
95
|
// Removed unused EXPRESSOTS_LOGO_MINIMAL constant
|
|
76
96
|
/**
|
|
77
97
|
* Color text helper.
|
|
@@ -118,7 +138,6 @@ class BannerGenerator {
|
|
|
118
138
|
const startupTime = Date.now() - this.startTime;
|
|
119
139
|
const memoryUsage = process.memoryUsage().heapUsed;
|
|
120
140
|
const memoryFormatted = (0, logger_metrics_js_1.formatMemory)(memoryUsage);
|
|
121
|
-
writeStdout("\n");
|
|
122
141
|
// Display logo based on style
|
|
123
142
|
switch (this.config.style) {
|
|
124
143
|
case "full":
|
|
@@ -131,7 +150,6 @@ class BannerGenerator {
|
|
|
131
150
|
this.displayMinimalBanner(port, environment, appInfo);
|
|
132
151
|
break;
|
|
133
152
|
}
|
|
134
|
-
writeStdout("\n");
|
|
135
153
|
}
|
|
136
154
|
/**
|
|
137
155
|
* Display full banner with clean 3-column layout.
|
|
@@ -139,6 +157,7 @@ class BannerGenerator {
|
|
|
139
157
|
* Optional (user-enabled): Features, Middleware Pipeline, Provider Registry, Resources
|
|
140
158
|
*/
|
|
141
159
|
displayFullBanner(port, environment, appInfo, metrics, features, config, startupTime, memoryFormatted, bannerData) {
|
|
160
|
+
writeStdout("\n");
|
|
142
161
|
// Banner box width is ~93 chars, calculate column widths for 3 columns
|
|
143
162
|
const totalWidth = 93;
|
|
144
163
|
const colWidth = 29;
|
|
@@ -149,7 +168,7 @@ class BannerGenerator {
|
|
|
149
168
|
// ══════════════════════════════════════════════════════════════════════
|
|
150
169
|
// Version info line (matches banner width)
|
|
151
170
|
// ══════════════════════════════════════════════════════════════════════
|
|
152
|
-
const frameworkVersion =
|
|
171
|
+
const frameworkVersion = framework_version_js_1.FRAMEWORK_VERSION;
|
|
153
172
|
const nodeVersion = process.version;
|
|
154
173
|
const platform = process.platform;
|
|
155
174
|
const appName = appInfo?.appName || "App";
|
|
@@ -385,27 +404,17 @@ class BannerGenerator {
|
|
|
385
404
|
writeStdout("\n");
|
|
386
405
|
}
|
|
387
406
|
/**
|
|
388
|
-
* Display compact banner.
|
|
407
|
+
* Display compact banner using structured log format (cloud-friendly).
|
|
389
408
|
*/
|
|
390
|
-
displayCompactBanner(port, environment, appInfo, metrics,
|
|
391
|
-
writeStdout(colorText(EXPRESSOTS_LOGO_COMPACT, "green"));
|
|
392
|
-
writeStdout("\n\n");
|
|
409
|
+
displayCompactBanner(port, environment, appInfo, metrics, _features, startupTime, memoryFormatted) {
|
|
393
410
|
const appName = appInfo?.appName || "App";
|
|
394
411
|
const appVersion = appInfo?.appVersion || "not provided";
|
|
395
|
-
writeStdout(
|
|
396
|
-
|
|
397
|
-
colorText(` | Node ${process.version}`, "blue") +
|
|
398
|
-
"\n");
|
|
399
|
-
writeStdout(colorText(`Environment: ${this.colorEnvironment(environment)}`, "yellow") +
|
|
400
|
-
colorText(` | Port: ${port}`, "blue") +
|
|
401
|
-
colorText(` | PID: ${process.pid}`, "blue") +
|
|
402
|
-
"\n");
|
|
412
|
+
writeStdout(logLine(`ExpressoTS v${framework_version_js_1.FRAMEWORK_VERSION} | ${appName} v${appVersion} | Node ${process.version}`));
|
|
413
|
+
writeStdout(logLine(`Environment: ${environment} | Port: ${port} | PID: ${process.pid}`));
|
|
403
414
|
if (metrics) {
|
|
404
|
-
writeStdout(
|
|
415
|
+
writeStdout(logLine(`Controllers: ${metrics.controllers} | Providers: ${metrics.providers} | Routes: ${metrics.routes}`));
|
|
405
416
|
}
|
|
406
|
-
writeStdout(
|
|
407
|
-
colorText(` | Memory: ${memoryFormatted}`, "yellow") +
|
|
408
|
-
"\n");
|
|
417
|
+
writeStdout(logLine(`Startup: ${startupTime.toFixed(2)}ms | Memory: ${memoryFormatted}`));
|
|
409
418
|
}
|
|
410
419
|
/**
|
|
411
420
|
* Display minimal banner.
|
|
@@ -4,12 +4,22 @@ exports.getDefaultLoggerConfig = getDefaultLoggerConfig;
|
|
|
4
4
|
const log_levels_js_1 = require("./utils/log-levels.js");
|
|
5
5
|
/**
|
|
6
6
|
* Default logger configuration.
|
|
7
|
+
*
|
|
8
|
+
* Honours `process.env.LOG_LEVEL` when set so that any logs emitted
|
|
9
|
+
* BEFORE the application's `globalConfiguration()` runs (e.g. interceptor
|
|
10
|
+
* registration during container construction) are gated by the user's
|
|
11
|
+
* desired log level instead of the development default of `DEBUG`.
|
|
12
|
+
* Falls back to `DEBUG` in development and `INFO` in production.
|
|
13
|
+
*
|
|
7
14
|
* @public API
|
|
8
15
|
*/
|
|
9
16
|
function getDefaultLoggerConfig() {
|
|
10
17
|
const isDevelopment = process.env.NODE_ENV !== "production";
|
|
18
|
+
const envLevel = process.env.LOG_LEVEL;
|
|
19
|
+
const defaultLevel = isDevelopment ? log_levels_js_1.LogLevel.DEBUG : log_levels_js_1.LogLevel.INFO;
|
|
20
|
+
const level = envLevel ? (0, log_levels_js_1.parseLogLevel)(envLevel) : defaultLevel;
|
|
11
21
|
return {
|
|
12
|
-
level
|
|
22
|
+
level,
|
|
13
23
|
transports: [], // Will be populated with ConsoleTransport by default
|
|
14
24
|
filters: {},
|
|
15
25
|
structured: !isDevelopment, // JSON in production, pretty in dev
|
|
@@ -7,6 +7,17 @@ exports.formatGroupedProd = formatGroupedProd;
|
|
|
7
7
|
const log_levels_js_1 = require("./utils/log-levels.js");
|
|
8
8
|
const color_codes_js_1 = require("../../console/color-codes.js");
|
|
9
9
|
const logger_redaction_js_1 = require("./logger.redaction.js");
|
|
10
|
+
/**
|
|
11
|
+
* Strip ANSI escape sequences (SGR colors, cursor moves, etc.) from a
|
|
12
|
+
* string. Cheap fast-path bails out when no escape character is present.
|
|
13
|
+
*/
|
|
14
|
+
// eslint-disable-next-line no-control-regex
|
|
15
|
+
const ANSI_ESCAPE_REGEX = /\u001b\[[\d;?]*[ -/]*[@-~]/g;
|
|
16
|
+
function stripAnsiEscapes(input) {
|
|
17
|
+
if (!input || input.indexOf("\u001b") === -1)
|
|
18
|
+
return input;
|
|
19
|
+
return input.replace(ANSI_ESCAPE_REGEX, "");
|
|
20
|
+
}
|
|
10
21
|
/**
|
|
11
22
|
* Format log entry for development (human-readable, colored).
|
|
12
23
|
* @param entry - Log entry to format
|
|
@@ -50,6 +61,13 @@ function formatDev(entry, options) {
|
|
|
50
61
|
if (processedEntry.flow) {
|
|
51
62
|
output += formatFlow(processedEntry.flow, 2);
|
|
52
63
|
}
|
|
64
|
+
// Strip ANSI escapes once at the end when colors are disabled. This is
|
|
65
|
+
// far simpler than threading a "useColors" flag through every nested
|
|
66
|
+
// `colorText(...)` call site and the perf cost (one regex pass over a
|
|
67
|
+
// log line) is negligible relative to the I/O that follows.
|
|
68
|
+
if (options?.colors === false) {
|
|
69
|
+
return stripAnsiEscapes(output);
|
|
70
|
+
}
|
|
53
71
|
return output;
|
|
54
72
|
}
|
|
55
73
|
/**
|
|
@@ -112,7 +130,7 @@ function formatTimestamp(date) {
|
|
|
112
130
|
*/
|
|
113
131
|
function getLevelColor(level) {
|
|
114
132
|
switch (level) {
|
|
115
|
-
case log_levels_js_1.LogLevel.
|
|
133
|
+
case log_levels_js_1.LogLevel.ALL:
|
|
116
134
|
return "white";
|
|
117
135
|
case log_levels_js_1.LogLevel.DEBUG:
|
|
118
136
|
return "blue";
|
|
@@ -337,6 +355,9 @@ function formatGroupedDev(groupedEntry, options) {
|
|
|
337
355
|
}
|
|
338
356
|
}
|
|
339
357
|
}
|
|
358
|
+
if (options?.colors === false) {
|
|
359
|
+
return stripAnsiEscapes(output);
|
|
360
|
+
}
|
|
340
361
|
return output;
|
|
341
362
|
}
|
|
342
363
|
/**
|
|
@@ -28,7 +28,7 @@ const logger_query_js_1 = require("./logger.query.js");
|
|
|
28
28
|
* - Automatic context detection (class/method names)
|
|
29
29
|
* - Request-scoped context via AsyncLocalStorage
|
|
30
30
|
* - Child logger creation with inherited context
|
|
31
|
-
* - Multiple log levels (
|
|
31
|
+
* - Multiple log levels (ALL, DEBUG, INFO, WARN, ERROR, FATAL, SILENT)
|
|
32
32
|
* - Pluggable transports (console, file, HTTP)
|
|
33
33
|
* @public API
|
|
34
34
|
*/
|
|
@@ -44,15 +44,27 @@ let Logger = Logger_1 = class Logger {
|
|
|
44
44
|
this.author = "Richard Zampieri";
|
|
45
45
|
this.repo = "https://github.com/expressots/expressots";
|
|
46
46
|
this.pid = process.pid;
|
|
47
|
-
|
|
48
|
-
//
|
|
47
|
+
// Merge module-level overrides on top of the built-in defaults so values
|
|
48
|
+
// set via Logger.configure(...) before container creation propagate to
|
|
49
|
+
// every instance. Caller-supplied transports replace the defaults, level
|
|
50
|
+
// is forwarded to the auto-installed console transport below.
|
|
51
|
+
const baseConfig = (0, logger_config_js_1.getDefaultLoggerConfig)();
|
|
52
|
+
this.config = {
|
|
53
|
+
...baseConfig,
|
|
54
|
+
...Logger_1.defaultOverrides,
|
|
55
|
+
};
|
|
56
|
+
// Initialize with default console transport if none provided.
|
|
57
|
+
// Aligning the transport's level with the resolved logger level
|
|
58
|
+
// (which already honours `process.env.LOG_LEVEL`) keeps both
|
|
59
|
+
// filters consistent for messages emitted before any explicit
|
|
60
|
+
// `logger.configure({ level })` call.
|
|
49
61
|
if (this.config.transports.length === 0) {
|
|
50
62
|
const isDevelopment = process.env.NODE_ENV !== "production";
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
];
|
|
63
|
+
const transport = isDevelopment
|
|
64
|
+
? console_transport_js_1.ConsoleTransport.forDevelopment()
|
|
65
|
+
: console_transport_js_1.ConsoleTransport.forProduction();
|
|
66
|
+
transport.level = (0, log_levels_js_1.parseLogLevel)(this.config.level);
|
|
67
|
+
this.config.transports = [transport];
|
|
56
68
|
}
|
|
57
69
|
this.transports = this.config.transports;
|
|
58
70
|
// Initialize grouping manager with default config
|
|
@@ -60,6 +72,37 @@ let Logger = Logger_1 = class Logger {
|
|
|
60
72
|
// Initialize query manager with default config
|
|
61
73
|
this.queryManager = new logger_query_js_1.LogQueryManager(this.config.query);
|
|
62
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Configure the default LoggerConfig used by every future `Logger`
|
|
77
|
+
* instance constructed in this process.
|
|
78
|
+
*
|
|
79
|
+
* Use this from application config files **before** bootstrap so the DI
|
|
80
|
+
* container's Logger picks up the correct level / transports / grouping /
|
|
81
|
+
* health / redaction settings without needing to inject and reconfigure it.
|
|
82
|
+
* Calls are merged: later calls override earlier ones, but unspecified
|
|
83
|
+
* keys keep their previously-set values.
|
|
84
|
+
*
|
|
85
|
+
* Already-constructed Logger instances are NOT mutated by this call —
|
|
86
|
+
* use the instance method `logger.configure(...)` to update a live one.
|
|
87
|
+
*
|
|
88
|
+
* @param config - Partial configuration to merge with the defaults.
|
|
89
|
+
* @public API
|
|
90
|
+
*/
|
|
91
|
+
static configure(config) {
|
|
92
|
+
Logger_1.defaultOverrides = {
|
|
93
|
+
...Logger_1.defaultOverrides,
|
|
94
|
+
...config,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Reset the module-level overrides set by `Logger.configure`. Useful in
|
|
99
|
+
* tests to undo cross-test pollution.
|
|
100
|
+
*
|
|
101
|
+
* @public API
|
|
102
|
+
*/
|
|
103
|
+
static resetConfigure() {
|
|
104
|
+
Logger_1.defaultOverrides = {};
|
|
105
|
+
}
|
|
63
106
|
/**
|
|
64
107
|
* Configure the logger.
|
|
65
108
|
* @param config - Partial configuration to merge with defaults
|
|
@@ -131,7 +174,7 @@ let Logger = Logger_1 = class Logger {
|
|
|
131
174
|
* @public API
|
|
132
175
|
*/
|
|
133
176
|
trace(message, data) {
|
|
134
|
-
this.log(log_levels_js_1.LogLevel.
|
|
177
|
+
this.log(log_levels_js_1.LogLevel.ALL, message, { data });
|
|
135
178
|
}
|
|
136
179
|
/**
|
|
137
180
|
* Log a debug message (detailed diagnostic).
|
|
@@ -739,6 +782,13 @@ let Logger = Logger_1 = class Logger {
|
|
|
739
782
|
}
|
|
740
783
|
};
|
|
741
784
|
exports.Logger = Logger;
|
|
785
|
+
/**
|
|
786
|
+
* Module-level overrides applied by `Logger.configure(...)` on top of the
|
|
787
|
+
* built-in defaults. Used by the constructor of every future `Logger`
|
|
788
|
+
* instance so application-wide config (e.g. log level, transports) can be
|
|
789
|
+
* set once before bootstrap, before any DI container exists.
|
|
790
|
+
*/
|
|
791
|
+
Logger.defaultOverrides = {};
|
|
742
792
|
exports.Logger = Logger = Logger_1 = __decorate([
|
|
743
793
|
(0, scope_binding_js_1.provideSingleton)(Logger, "builtin"),
|
|
744
794
|
__metadata("design:paramtypes", [])
|
|
@@ -3,6 +3,35 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ConsoleTransport = void 0;
|
|
4
4
|
const log_levels_js_1 = require("../utils/log-levels.js");
|
|
5
5
|
const logger_formatter_js_1 = require("../logger.formatter.js");
|
|
6
|
+
/**
|
|
7
|
+
* Decide whether ANSI color codes should be emitted by default.
|
|
8
|
+
*
|
|
9
|
+
* Order of precedence (industry standard, matches chalk / supports-color):
|
|
10
|
+
* 1. `NO_COLOR` env var (any non-empty value) → never colors
|
|
11
|
+
* 2. `FORCE_COLOR` env var (any non-"0"/"false" value) → always colors
|
|
12
|
+
* 3. Process running in production → never colors
|
|
13
|
+
* 4. Stdout is a TTY → colors
|
|
14
|
+
* 5. Otherwise (pipes, redirects, cloud log capture) → no colors
|
|
15
|
+
*
|
|
16
|
+
* This means cloud platforms like Azure App Service, AWS CloudWatch,
|
|
17
|
+
* Heroku, Docker, Kubernetes, etc. — which all capture stdout into a
|
|
18
|
+
* non-TTY pipe — receive plain text by default, without users having
|
|
19
|
+
* to configure anything.
|
|
20
|
+
*/
|
|
21
|
+
function detectColorsDefault() {
|
|
22
|
+
const noColor = process.env.NO_COLOR;
|
|
23
|
+
if (noColor !== undefined && noColor !== "")
|
|
24
|
+
return false;
|
|
25
|
+
const forceColor = process.env.FORCE_COLOR;
|
|
26
|
+
if (forceColor !== undefined &&
|
|
27
|
+
forceColor !== "0" &&
|
|
28
|
+
forceColor !== "false") {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
if (process.env.NODE_ENV === "production")
|
|
32
|
+
return false;
|
|
33
|
+
return Boolean(process.stdout && process.stdout.isTTY);
|
|
34
|
+
}
|
|
6
35
|
/**
|
|
7
36
|
* Console transport for logging to stdout/stderr.
|
|
8
37
|
* @public API
|
|
@@ -18,7 +47,7 @@ class ConsoleTransport {
|
|
|
18
47
|
this.enabled = options?.enabled ?? true;
|
|
19
48
|
this.structured =
|
|
20
49
|
options?.structured ?? process.env.NODE_ENV === "production";
|
|
21
|
-
this.colors = options?.colors ??
|
|
50
|
+
this.colors = options?.colors ?? detectColorsDefault();
|
|
22
51
|
this.pretty = options?.pretty ?? process.env.NODE_ENV !== "production";
|
|
23
52
|
// Enable redaction by default in production
|
|
24
53
|
this.redact = options?.redact ?? process.env.NODE_ENV === "production";
|
|
@@ -26,6 +55,13 @@ class ConsoleTransport {
|
|
|
26
55
|
}
|
|
27
56
|
/**
|
|
28
57
|
* Create a console transport optimized for development.
|
|
58
|
+
*
|
|
59
|
+
* Colors are auto-detected: they're emitted when stdout is a TTY
|
|
60
|
+
* (your terminal) and disabled when stdout is piped or captured by
|
|
61
|
+
* a cloud log collector (Azure App Service, AWS CloudWatch, Heroku,
|
|
62
|
+
* Docker, Kubernetes, etc.). Respects the standard `NO_COLOR` and
|
|
63
|
+
* `FORCE_COLOR` environment variables.
|
|
64
|
+
*
|
|
29
65
|
* @param redact - Enable redaction (default: false for development)
|
|
30
66
|
* @returns ConsoleTransport configured for development
|
|
31
67
|
* @public API
|
|
@@ -34,7 +70,7 @@ class ConsoleTransport {
|
|
|
34
70
|
return new ConsoleTransport({
|
|
35
71
|
level: log_levels_js_1.LogLevel.DEBUG,
|
|
36
72
|
structured: false,
|
|
37
|
-
colors
|
|
73
|
+
// Omit `colors` so the constructor's auto-detect kicks in.
|
|
38
74
|
pretty: true,
|
|
39
75
|
redact, // Usually disabled in development for easier debugging
|
|
40
76
|
});
|
|
@@ -58,17 +94,44 @@ class ConsoleTransport {
|
|
|
58
94
|
if (!this.enabled || !(0, log_levels_js_1.shouldLog)(entry.level, this.level)) {
|
|
59
95
|
return;
|
|
60
96
|
}
|
|
61
|
-
// Build format options with redaction settings
|
|
97
|
+
// Build format options with redaction + color settings. The color
|
|
98
|
+
// flag is honoured by `formatDev` / `formatGroupedDev`; `formatProd`
|
|
99
|
+
// (structured JSON) never emits color regardless.
|
|
62
100
|
const formatOptions = {
|
|
63
101
|
redact: this.redact,
|
|
64
102
|
redactor: this.redactor,
|
|
103
|
+
colors: this.colors,
|
|
65
104
|
};
|
|
66
105
|
const formatted = this.structured
|
|
67
106
|
? (0, logger_formatter_js_1.formatProd)(entry, formatOptions)
|
|
68
107
|
: (0, logger_formatter_js_1.formatDev)(entry, formatOptions);
|
|
69
|
-
//
|
|
70
|
-
const
|
|
71
|
-
|
|
108
|
+
// Strip trailing newline since console.* methods append their own.
|
|
109
|
+
const msg = formatted.endsWith("\n") ? formatted.slice(0, -1) : formatted;
|
|
110
|
+
// Route through console methods so Studio's LogCapture (which
|
|
111
|
+
// intercepts console.*) can forward these entries to the Live Logs UI.
|
|
112
|
+
// The level mapping mirrors the level chips Studio renders so messages
|
|
113
|
+
// land under the expected filter. We pass a single pre-formatted string
|
|
114
|
+
// so util.format never tries to interpret stray "%s"/"%d" tokens in
|
|
115
|
+
// user-supplied messages.
|
|
116
|
+
switch (entry.level) {
|
|
117
|
+
case log_levels_js_1.LogLevel.DEBUG:
|
|
118
|
+
case log_levels_js_1.LogLevel.ALL:
|
|
119
|
+
console.debug(msg);
|
|
120
|
+
break;
|
|
121
|
+
case log_levels_js_1.LogLevel.INFO:
|
|
122
|
+
console.info(msg);
|
|
123
|
+
break;
|
|
124
|
+
case log_levels_js_1.LogLevel.WARN:
|
|
125
|
+
console.warn(msg);
|
|
126
|
+
break;
|
|
127
|
+
case log_levels_js_1.LogLevel.ERROR:
|
|
128
|
+
case log_levels_js_1.LogLevel.FATAL:
|
|
129
|
+
console.error(msg);
|
|
130
|
+
break;
|
|
131
|
+
default:
|
|
132
|
+
console.log(msg);
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
72
135
|
}
|
|
73
136
|
flush() {
|
|
74
137
|
// Console doesn't need flushing
|
|
@@ -87,29 +87,34 @@ class FileTransport {
|
|
|
87
87
|
if (!this.enabled || !(0, log_levels_js_1.shouldLog)(entry.level, this.level)) {
|
|
88
88
|
return;
|
|
89
89
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
this.currentFileSize = await this.getFileSize(filename);
|
|
98
|
-
}
|
|
99
|
-
await this.ensureDirectory();
|
|
100
|
-
const filePath = (0, path_1.join)(this.directory, this.currentFilename);
|
|
101
|
-
const formatted = (0, logger_formatter_js_1.formatProd)(entry) + "\n";
|
|
102
|
-
const entrySize = Buffer.byteLength(formatted, "utf8");
|
|
90
|
+
// Wrap the entire write pipeline in a single try/catch.
|
|
91
|
+
//
|
|
92
|
+
// FileTransport must NEVER throw out of `log()` — a logger that crashes
|
|
93
|
+
// the request that just wrote to it would be worse than a silent drop.
|
|
94
|
+
// We log a single line to stderr and move on; this matches the
|
|
95
|
+
// ConsoleTransport contract and keeps the framework's "logging never
|
|
96
|
+
// takes down the app" invariant.
|
|
103
97
|
try {
|
|
98
|
+
const filename = this.getFilename();
|
|
99
|
+
const shouldRotate = this.shouldRotate(filename);
|
|
100
|
+
if (shouldRotate) {
|
|
101
|
+
await this.rotateFile(filename);
|
|
102
|
+
}
|
|
103
|
+
if (filename !== this.currentFilename) {
|
|
104
|
+
this.currentFilename = filename;
|
|
105
|
+
this.currentFileSize = await this.getFileSize(filename);
|
|
106
|
+
}
|
|
107
|
+
await this.ensureDirectory();
|
|
108
|
+
const filePath = (0, path_1.join)(this.directory, this.currentFilename);
|
|
109
|
+
const formatted = (0, logger_formatter_js_1.formatProd)(entry) + "\n";
|
|
110
|
+
const entrySize = Buffer.byteLength(formatted, "utf8");
|
|
104
111
|
await fs_1.promises.appendFile(filePath, formatted, "utf8");
|
|
105
112
|
this.currentFileSize += entrySize;
|
|
106
|
-
// Check if we need to rotate after this write
|
|
107
113
|
if (this.maxSize > 0 && this.currentFileSize >= this.maxSize) {
|
|
108
114
|
await this.rotateFile(this.currentFilename);
|
|
109
115
|
}
|
|
110
116
|
}
|
|
111
117
|
catch (error) {
|
|
112
|
-
// Silently fail to avoid log loops
|
|
113
118
|
console.error(`[FileTransport] Failed to write log:`, error);
|
|
114
119
|
}
|
|
115
120
|
}
|
|
@@ -217,13 +222,17 @@ class FileTransport {
|
|
|
217
222
|
}
|
|
218
223
|
}
|
|
219
224
|
startCleanupInterval() {
|
|
220
|
-
// Run cleanup every hour
|
|
221
225
|
this.cleanupInterval = setInterval(() => {
|
|
222
226
|
this.cleanupOldFiles().catch((error) => {
|
|
223
227
|
console.error(`[FileTransport] Cleanup failed:`, error);
|
|
224
228
|
});
|
|
225
|
-
}, 60 * 60 * 1000);
|
|
226
|
-
//
|
|
229
|
+
}, 60 * 60 * 1000);
|
|
230
|
+
// unref() so the cleanup timer never keeps the event loop alive on its own.
|
|
231
|
+
// Without this a short-lived script that uses FileTransport would hang
|
|
232
|
+
// for an hour at exit waiting on the next tick.
|
|
233
|
+
if (typeof this.cleanupInterval.unref === "function") {
|
|
234
|
+
this.cleanupInterval.unref();
|
|
235
|
+
}
|
|
227
236
|
this.cleanupOldFiles().catch((error) => {
|
|
228
237
|
console.error(`[FileTransport] Initial cleanup failed:`, error);
|
|
229
238
|
});
|
|
@@ -11,8 +11,8 @@ exports.shouldLog = shouldLog;
|
|
|
11
11
|
*/
|
|
12
12
|
var LogLevel;
|
|
13
13
|
(function (LogLevel) {
|
|
14
|
-
/**
|
|
15
|
-
LogLevel[LogLevel["
|
|
14
|
+
/** Show all logs (ultra-detailed diagnostic information, function entry/exit) */
|
|
15
|
+
LogLevel[LogLevel["ALL"] = 0] = "ALL";
|
|
16
16
|
/** Detailed diagnostic information for debugging */
|
|
17
17
|
LogLevel[LogLevel["DEBUG"] = 1] = "DEBUG";
|
|
18
18
|
/** General informational messages */
|
|
@@ -47,8 +47,9 @@ function parseLogLevel(level) {
|
|
|
47
47
|
return LogLevel.INFO;
|
|
48
48
|
}
|
|
49
49
|
switch (upperLevel) {
|
|
50
|
+
case "ALL":
|
|
50
51
|
case "TRACE":
|
|
51
|
-
return LogLevel.
|
|
52
|
+
return LogLevel.ALL;
|
|
52
53
|
case "DEBUG":
|
|
53
54
|
return LogLevel.DEBUG;
|
|
54
55
|
case "INFO":
|
|
@@ -73,8 +74,8 @@ function parseLogLevel(level) {
|
|
|
73
74
|
*/
|
|
74
75
|
function logLevelToString(level) {
|
|
75
76
|
switch (level) {
|
|
76
|
-
case LogLevel.
|
|
77
|
-
return "
|
|
77
|
+
case LogLevel.ALL:
|
|
78
|
+
return "ALL";
|
|
78
79
|
case LogLevel.DEBUG:
|
|
79
80
|
return "DEBUG";
|
|
80
81
|
case LogLevel.INFO:
|
|
@@ -3,12 +3,19 @@
|
|
|
3
3
|
* Validation Adapters
|
|
4
4
|
* @module @expressots/core/validation/adapters
|
|
5
5
|
*
|
|
6
|
-
* Built-in adapters for validation libraries.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* Built-in adapters for validation libraries. The validation libraries
|
|
7
|
+
* themselves (`class-validator`, `zod`, `yup`) are *optional peer
|
|
8
|
+
* dependencies* — install only the one(s) you actually use.
|
|
9
|
+
*
|
|
10
|
+
* Additional Joi adapter is on the roadmap.
|
|
10
11
|
*/
|
|
11
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.ClassValidatorAdapter = void 0;
|
|
13
|
+
exports.createYupValidator = exports.YupValidatorAdapter = exports.createZodValidator = exports.ZodValidatorAdapter = exports.ClassValidatorAdapter = void 0;
|
|
13
14
|
var class_validator_adapter_js_1 = require("./class-validator.adapter.js");
|
|
14
15
|
Object.defineProperty(exports, "ClassValidatorAdapter", { enumerable: true, get: function () { return class_validator_adapter_js_1.ClassValidatorAdapter; } });
|
|
16
|
+
var zod_adapter_js_1 = require("./zod.adapter.js");
|
|
17
|
+
Object.defineProperty(exports, "ZodValidatorAdapter", { enumerable: true, get: function () { return zod_adapter_js_1.ZodValidatorAdapter; } });
|
|
18
|
+
Object.defineProperty(exports, "createZodValidator", { enumerable: true, get: function () { return zod_adapter_js_1.createZodValidator; } });
|
|
19
|
+
var yup_adapter_js_1 = require("./yup.adapter.js");
|
|
20
|
+
Object.defineProperty(exports, "YupValidatorAdapter", { enumerable: true, get: function () { return yup_adapter_js_1.YupValidatorAdapter; } });
|
|
21
|
+
Object.defineProperty(exports, "createYupValidator", { enumerable: true, get: function () { return yup_adapter_js_1.createYupValidator; } });
|