@revealui/utils 0.2.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/LICENSE +22 -0
- package/README.md +74 -0
- package/dist/chunk-KUMOGLHP.js +32 -0
- package/dist/chunk-KUMOGLHP.js.map +1 -0
- package/dist/chunk-QR4YAGWO.js +264 -0
- package/dist/chunk-QR4YAGWO.js.map +1 -0
- package/dist/chunk-UEYUNTMY.js +8 -0
- package/dist/chunk-UEYUNTMY.js.map +1 -0
- package/dist/database/index.d.ts +60 -0
- package/dist/database/index.js +9 -0
- package/dist/database/index.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/logger/index.d.ts +127 -0
- package/dist/logger/index.js +17 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/validation/index.d.ts +16 -0
- package/dist/validation/index.js +7 -0
- package/dist/validation/index.js.map +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 RevealUI Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# @revealui/utils
|
|
2
|
+
|
|
3
|
+
Shared utilities for RevealUI - logger, SSL config, and common helpers.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
This package contains zero-dependency utilities that are used across multiple packages in the RevealUI monorepo. It was created to break circular dependencies between `@revealui/core`, `@revealui/db`, and `@revealui/contracts`.
|
|
8
|
+
|
|
9
|
+
## Contents
|
|
10
|
+
|
|
11
|
+
### Logger
|
|
12
|
+
Structured logging infrastructure with support for:
|
|
13
|
+
- Multiple log levels (debug, info, warn, error, fatal)
|
|
14
|
+
- Context propagation
|
|
15
|
+
- Pretty printing for development
|
|
16
|
+
- Remote logging support
|
|
17
|
+
- Child loggers with inherited context
|
|
18
|
+
|
|
19
|
+
### Database Utilities
|
|
20
|
+
- SSL configuration for PostgreSQL connections
|
|
21
|
+
- Connection string parsing
|
|
22
|
+
- Security validation for production environments
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
// Import logger
|
|
28
|
+
import { logger, createLogger } from '@revealui/utils'
|
|
29
|
+
|
|
30
|
+
// Use default logger
|
|
31
|
+
logger.info('Application started')
|
|
32
|
+
|
|
33
|
+
// Create child logger with context
|
|
34
|
+
const requestLogger = createLogger({ requestId: '123' })
|
|
35
|
+
requestLogger.info('Processing request')
|
|
36
|
+
|
|
37
|
+
// Import database utilities
|
|
38
|
+
import { getSSLConfig } from '@revealui/utils/database'
|
|
39
|
+
|
|
40
|
+
const sslConfig = getSSLConfig(process.env.DATABASE_URL)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Why This Package Exists
|
|
44
|
+
|
|
45
|
+
Previously, these utilities lived in `@revealui/core`, which created a circular dependency:
|
|
46
|
+
```
|
|
47
|
+
contracts → db → core → contracts (circular!)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
By extracting shared utilities to `@revealui/utils`, we get a clean dependency graph:
|
|
51
|
+
```
|
|
52
|
+
utils (no dependencies)
|
|
53
|
+
↑
|
|
54
|
+
├── contracts
|
|
55
|
+
├── db
|
|
56
|
+
└── core
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Development
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Build
|
|
63
|
+
pnpm build
|
|
64
|
+
|
|
65
|
+
# Type check
|
|
66
|
+
pnpm typecheck
|
|
67
|
+
|
|
68
|
+
# Watch mode
|
|
69
|
+
pnpm dev
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## License
|
|
73
|
+
|
|
74
|
+
MIT
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// src/database/ssl-config.ts
|
|
2
|
+
function getSSLConfig(connectionString) {
|
|
3
|
+
try {
|
|
4
|
+
const url = new URL(connectionString);
|
|
5
|
+
const sslmode = url.searchParams.get("sslmode");
|
|
6
|
+
if (!sslmode || sslmode === "disable") {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
if (process.env.NODE_ENV !== "production" && process.env.DATABASE_SSL_REJECT_UNAUTHORIZED === "false") {
|
|
10
|
+
return { rejectUnauthorized: false };
|
|
11
|
+
}
|
|
12
|
+
return { rejectUnauthorized: true };
|
|
13
|
+
} catch (_error) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function validateSSLConfig(connectionString, environment = process.env.NODE_ENV || "development") {
|
|
18
|
+
const sslConfig = getSSLConfig(connectionString);
|
|
19
|
+
if (environment === "production" && sslConfig === false) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
if (environment === "production" && sslConfig && !sslConfig.rejectUnauthorized) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
getSSLConfig,
|
|
30
|
+
validateSSLConfig
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=chunk-KUMOGLHP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/database/ssl-config.ts"],"sourcesContent":["/**\n * SSL Configuration Utility\n *\n * Provides centralized SSL configuration for PostgreSQL connections based on\n * connection string sslmode parameter and environment variables.\n *\n * Extracted from @revealui/core to break circular dependencies\n *\n * @module ssl-config\n */\n\n/**\n * PostgreSQL SSL configuration options\n */\nexport interface SSLConfig {\n rejectUnauthorized: boolean\n}\n\n/**\n * Determines the appropriate SSL configuration for a PostgreSQL connection\n * based on the connection string's sslmode parameter.\n *\n * SSL Modes (aligned with PostgreSQL libpq standards):\n * - `disable`: No SSL connection\n * - `require`: SSL connection with certificate verification\n * - `verify-full`: Full SSL verification (same as require in pg v9+)\n * - `verify-ca`: CA verification (treated as verify-full)\n *\n * Environment Override:\n * - `DATABASE_SSL_REJECT_UNAUTHORIZED=false`: Force skip certificate verification\n * (DEVELOPMENT ONLY - use for self-signed certificates in local environments)\n *\n * @param connectionString - PostgreSQL connection string (may include sslmode parameter)\n * @returns SSL configuration object or false to disable SSL\n *\n * @example\n * ```typescript\n * // Connection string with SSL required\n * const ssl = getSSLConfig('postgresql://user:pass@host/db?sslmode=require')\n * // Returns: { rejectUnauthorized: true }\n *\n * // Connection string without SSL\n * const ssl = getSSLConfig('postgresql://localhost:5432/db')\n * // Returns: false\n *\n * // Development override for self-signed certificates\n * process.env.DATABASE_SSL_REJECT_UNAUTHORIZED = 'false'\n * const ssl = getSSLConfig('postgresql://user:pass@host/db?sslmode=require')\n * // Returns: { rejectUnauthorized: false }\n * ```\n */\nexport function getSSLConfig(connectionString: string): SSLConfig | false {\n try {\n // Parse connection string\n const url = new URL(connectionString)\n const sslmode = url.searchParams.get('sslmode')\n\n // No SSL if sslmode is explicitly disabled or not specified\n if (!sslmode || sslmode === 'disable') {\n return false\n }\n\n // Environment override for local development with self-signed certificates\n // This should ONLY be used in development environments\n // SECURITY: Explicitly check NODE_ENV to prevent accidental use in production\n if (\n process.env.NODE_ENV !== 'production' &&\n process.env.DATABASE_SSL_REJECT_UNAUTHORIZED === 'false'\n ) {\n return { rejectUnauthorized: false }\n }\n\n // Default: verify certificates (security best practice)\n // Handles: require, verify-full, verify-ca, prefer\n // In pg v9+, these will all use verify-full semantics\n return { rejectUnauthorized: true }\n } catch (_error) {\n // If URL parsing fails, assume local connection without SSL\n // Silently fallback to no SSL for invalid connection strings\n return false\n }\n}\n\n/**\n * Validates SSL configuration for production environments.\n * Warns if insecure SSL settings are detected in production.\n *\n * @param connectionString - PostgreSQL connection string\n * @param environment - Current environment (e.g., 'production', 'development')\n */\nexport function validateSSLConfig(\n connectionString: string,\n environment: string = process.env.NODE_ENV || 'development',\n): boolean {\n const sslConfig = getSSLConfig(connectionString)\n\n // Check if SSL is disabled in production\n if (environment === 'production' && sslConfig === false) {\n return false // SSL disabled in production - security risk\n }\n\n // Check if certificate verification is disabled in production\n if (environment === 'production' && sslConfig && !sslConfig.rejectUnauthorized) {\n return false // Certificate verification disabled - security risk\n }\n\n return true // SSL configuration is valid\n}\n"],"mappings":";AAmDO,SAAS,aAAa,kBAA6C;AACxE,MAAI;AAEF,UAAM,MAAM,IAAI,IAAI,gBAAgB;AACpC,UAAM,UAAU,IAAI,aAAa,IAAI,SAAS;AAG9C,QAAI,CAAC,WAAW,YAAY,WAAW;AACrC,aAAO;AAAA,IACT;AAKA,QACE,QAAQ,IAAI,aAAa,gBACzB,QAAQ,IAAI,qCAAqC,SACjD;AACA,aAAO,EAAE,oBAAoB,MAAM;AAAA,IACrC;AAKA,WAAO,EAAE,oBAAoB,KAAK;AAAA,EACpC,SAAS,QAAQ;AAGf,WAAO;AAAA,EACT;AACF;AASO,SAAS,kBACd,kBACA,cAAsB,QAAQ,IAAI,YAAY,eACrC;AACT,QAAM,YAAY,aAAa,gBAAgB;AAG/C,MAAI,gBAAgB,gBAAgB,cAAc,OAAO;AACvD,WAAO;AAAA,EACT;AAGA,MAAI,gBAAgB,gBAAgB,aAAa,CAAC,UAAU,oBAAoB;AAC9E,WAAO;AAAA,EACT;AAEA,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
// src/logger/index.ts
|
|
2
|
+
var LOG_LEVELS = {
|
|
3
|
+
debug: 0,
|
|
4
|
+
info: 1,
|
|
5
|
+
warn: 2,
|
|
6
|
+
error: 3,
|
|
7
|
+
fatal: 4
|
|
8
|
+
};
|
|
9
|
+
var Logger = class _Logger {
|
|
10
|
+
config;
|
|
11
|
+
context = {};
|
|
12
|
+
extraHandlers = [];
|
|
13
|
+
constructor(config = {}) {
|
|
14
|
+
this.config = {
|
|
15
|
+
level: config.level || "info",
|
|
16
|
+
enabled: config.enabled !== void 0 ? config.enabled : true,
|
|
17
|
+
pretty: config.pretty !== void 0 ? config.pretty : process.env.NODE_ENV !== "production",
|
|
18
|
+
includeTimestamp: config.includeTimestamp !== void 0 ? config.includeTimestamp : true,
|
|
19
|
+
includeStack: config.includeStack !== void 0 ? config.includeStack : true,
|
|
20
|
+
destination: config.destination || "console",
|
|
21
|
+
remoteUrl: config.remoteUrl || "",
|
|
22
|
+
onLog: config.onLog || (() => {
|
|
23
|
+
})
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Register an additional log handler (e.g. DB transport).
|
|
28
|
+
* Called after every log entry, fire-and-forget. Must not throw.
|
|
29
|
+
*/
|
|
30
|
+
addLogHandler(handler) {
|
|
31
|
+
this.extraHandlers.push(handler);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Set global context
|
|
35
|
+
*/
|
|
36
|
+
setContext(context) {
|
|
37
|
+
this.context = { ...this.context, ...context };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Clear global context
|
|
41
|
+
*/
|
|
42
|
+
clearContext() {
|
|
43
|
+
this.context = {};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Debug log
|
|
47
|
+
*/
|
|
48
|
+
debug(message, context) {
|
|
49
|
+
this.log("debug", message, context);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Info log
|
|
53
|
+
*/
|
|
54
|
+
info(message, context) {
|
|
55
|
+
this.log("info", message, context);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Warning log
|
|
59
|
+
*/
|
|
60
|
+
warn(message, context) {
|
|
61
|
+
this.log("warn", message, context);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Error log
|
|
65
|
+
*/
|
|
66
|
+
error(message, error, context) {
|
|
67
|
+
const errorContext = error ? {
|
|
68
|
+
error: {
|
|
69
|
+
name: error.name,
|
|
70
|
+
message: error.message,
|
|
71
|
+
stack: this.config.includeStack ? error.stack : void 0,
|
|
72
|
+
cause: error.cause
|
|
73
|
+
}
|
|
74
|
+
} : {};
|
|
75
|
+
this.log("error", message, { ...context, ...errorContext });
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Fatal log
|
|
79
|
+
*/
|
|
80
|
+
fatal(message, error, context) {
|
|
81
|
+
const errorContext = error ? {
|
|
82
|
+
error: {
|
|
83
|
+
name: error.name,
|
|
84
|
+
message: error.message,
|
|
85
|
+
stack: this.config.includeStack ? error.stack : void 0,
|
|
86
|
+
cause: error.cause
|
|
87
|
+
}
|
|
88
|
+
} : {};
|
|
89
|
+
this.log("fatal", message, { ...context, ...errorContext });
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Core logging method
|
|
93
|
+
*/
|
|
94
|
+
log(level, message, context) {
|
|
95
|
+
if (!this.config.enabled) return;
|
|
96
|
+
if (LOG_LEVELS[level] < LOG_LEVELS[this.config.level]) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const entry = {
|
|
100
|
+
timestamp: this.config.includeTimestamp ? (/* @__PURE__ */ new Date()).toISOString() : "",
|
|
101
|
+
level,
|
|
102
|
+
message,
|
|
103
|
+
context: { ...this.context, ...context }
|
|
104
|
+
};
|
|
105
|
+
if (entry.context?.error) {
|
|
106
|
+
entry.error = entry.context.error;
|
|
107
|
+
entry.context.error = void 0;
|
|
108
|
+
}
|
|
109
|
+
this.config.onLog(entry);
|
|
110
|
+
for (const handler of this.extraHandlers) {
|
|
111
|
+
handler(entry);
|
|
112
|
+
}
|
|
113
|
+
this.output(entry);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Output log entry
|
|
117
|
+
*/
|
|
118
|
+
output(entry) {
|
|
119
|
+
switch (this.config.destination) {
|
|
120
|
+
case "console":
|
|
121
|
+
this.outputConsole(entry);
|
|
122
|
+
break;
|
|
123
|
+
case "file":
|
|
124
|
+
this.outputFile(entry);
|
|
125
|
+
break;
|
|
126
|
+
case "remote":
|
|
127
|
+
this.outputRemote(entry);
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Output to console
|
|
133
|
+
*/
|
|
134
|
+
outputConsole(entry) {
|
|
135
|
+
const output = this.config.pretty ? this.formatPretty(entry) : JSON.stringify(entry);
|
|
136
|
+
switch (entry.level) {
|
|
137
|
+
case "debug":
|
|
138
|
+
console.debug(output);
|
|
139
|
+
break;
|
|
140
|
+
case "info":
|
|
141
|
+
console.info(output);
|
|
142
|
+
break;
|
|
143
|
+
case "warn":
|
|
144
|
+
console.warn(output);
|
|
145
|
+
break;
|
|
146
|
+
case "error":
|
|
147
|
+
case "fatal":
|
|
148
|
+
console.error(output);
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Output to file
|
|
154
|
+
*/
|
|
155
|
+
outputFile(entry) {
|
|
156
|
+
console.log(JSON.stringify(entry));
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Output to remote service
|
|
160
|
+
*/
|
|
161
|
+
async outputRemote(entry) {
|
|
162
|
+
if (!this.config.remoteUrl) return;
|
|
163
|
+
try {
|
|
164
|
+
await fetch(this.config.remoteUrl, {
|
|
165
|
+
method: "POST",
|
|
166
|
+
headers: {
|
|
167
|
+
"Content-Type": "application/json"
|
|
168
|
+
},
|
|
169
|
+
body: JSON.stringify(entry)
|
|
170
|
+
});
|
|
171
|
+
} catch (error) {
|
|
172
|
+
console.error("Failed to send log to remote:", error);
|
|
173
|
+
this.outputConsole(entry);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Format log entry for pretty printing
|
|
178
|
+
*/
|
|
179
|
+
formatPretty(entry) {
|
|
180
|
+
const levelColors = {
|
|
181
|
+
debug: "\x1B[36m",
|
|
182
|
+
// Cyan
|
|
183
|
+
info: "\x1B[32m",
|
|
184
|
+
// Green
|
|
185
|
+
warn: "\x1B[33m",
|
|
186
|
+
// Yellow
|
|
187
|
+
error: "\x1B[31m",
|
|
188
|
+
// Red
|
|
189
|
+
fatal: "\x1B[35m"
|
|
190
|
+
// Magenta
|
|
191
|
+
};
|
|
192
|
+
const reset = "\x1B[0m";
|
|
193
|
+
const color = levelColors[entry.level];
|
|
194
|
+
const parts = [];
|
|
195
|
+
if (entry.timestamp) {
|
|
196
|
+
parts.push(`\x1B[90m${entry.timestamp}${reset}`);
|
|
197
|
+
}
|
|
198
|
+
parts.push(`${color}${entry.level.toUpperCase()}${reset}`);
|
|
199
|
+
parts.push(entry.message);
|
|
200
|
+
if (entry.context && Object.keys(entry.context).length > 0) {
|
|
201
|
+
parts.push(JSON.stringify(entry.context, null, 2));
|
|
202
|
+
}
|
|
203
|
+
if (entry.error) {
|
|
204
|
+
parts.push(`
|
|
205
|
+
${color}Error: ${entry.error.message}${reset}`);
|
|
206
|
+
if (entry.error.stack) {
|
|
207
|
+
parts.push(entry.error.stack);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return parts.join(" ");
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Create child logger with additional context
|
|
214
|
+
*/
|
|
215
|
+
child(context) {
|
|
216
|
+
const childLogger = new _Logger(this.config);
|
|
217
|
+
childLogger.setContext({ ...this.context, ...context });
|
|
218
|
+
for (const handler of this.extraHandlers) {
|
|
219
|
+
childLogger.addLogHandler(handler);
|
|
220
|
+
}
|
|
221
|
+
return childLogger;
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
var logger = new Logger({
|
|
225
|
+
level: process.env.LOG_LEVEL || "info",
|
|
226
|
+
pretty: process.env.NODE_ENV !== "production"
|
|
227
|
+
});
|
|
228
|
+
function createLogger(context) {
|
|
229
|
+
return logger.child(context);
|
|
230
|
+
}
|
|
231
|
+
function logError(error, context) {
|
|
232
|
+
logger.error(error.message, error, context);
|
|
233
|
+
}
|
|
234
|
+
function logAudit(action, context) {
|
|
235
|
+
logger.info(`Audit: ${action}`, {
|
|
236
|
+
...context,
|
|
237
|
+
audit: true,
|
|
238
|
+
action
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
function logQuery(query, duration, context) {
|
|
242
|
+
logger.debug("Database query", {
|
|
243
|
+
...context,
|
|
244
|
+
query,
|
|
245
|
+
duration
|
|
246
|
+
});
|
|
247
|
+
if (duration > 1e3) {
|
|
248
|
+
logger.warn("Slow query detected", {
|
|
249
|
+
...context,
|
|
250
|
+
query,
|
|
251
|
+
duration
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export {
|
|
257
|
+
Logger,
|
|
258
|
+
logger,
|
|
259
|
+
createLogger,
|
|
260
|
+
logError,
|
|
261
|
+
logAudit,
|
|
262
|
+
logQuery
|
|
263
|
+
};
|
|
264
|
+
//# sourceMappingURL=chunk-QR4YAGWO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/logger/index.ts"],"sourcesContent":["/**\n * Structured Logging Infrastructure\n *\n * Provides consistent, structured logging across the application\n * Extracted from @revealui/core to break circular dependencies\n */\n\n/* eslint-disable no-console */\n/* console-allowed */\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal'\n\nexport interface LogContext {\n [key: string]: unknown\n userId?: string\n requestId?: string\n sessionId?: string\n traceId?: string\n spanId?: string\n}\n\nexport interface LogEntry {\n timestamp: string\n level: LogLevel\n message: string\n context?: LogContext\n error?: {\n name: string\n message: string\n stack?: string\n cause?: unknown\n }\n metadata?: Record<string, unknown>\n}\n\nexport interface LoggerConfig {\n level?: LogLevel\n enabled?: boolean\n pretty?: boolean\n includeTimestamp?: boolean\n includeStack?: boolean\n destination?: 'console' | 'file' | 'remote'\n remoteUrl?: string\n onLog?: (entry: LogEntry) => void\n}\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n fatal: 4,\n}\n\nexport class Logger {\n private config: Required<LoggerConfig>\n private context: LogContext = {}\n private extraHandlers: Array<(entry: LogEntry) => void> = []\n\n constructor(config: LoggerConfig = {}) {\n this.config = {\n level: config.level || 'info',\n enabled: config.enabled !== undefined ? config.enabled : true,\n pretty: config.pretty !== undefined ? config.pretty : process.env.NODE_ENV !== 'production',\n includeTimestamp: config.includeTimestamp !== undefined ? config.includeTimestamp : true,\n includeStack: config.includeStack !== undefined ? config.includeStack : true,\n destination: config.destination || 'console',\n remoteUrl: config.remoteUrl || '',\n onLog:\n config.onLog ||\n (() => {\n // No-op function\n }),\n }\n }\n\n /**\n * Register an additional log handler (e.g. DB transport).\n * Called after every log entry, fire-and-forget. Must not throw.\n */\n addLogHandler(handler: (entry: LogEntry) => void): void {\n this.extraHandlers.push(handler)\n }\n\n /**\n * Set global context\n */\n setContext(context: LogContext): void {\n this.context = { ...this.context, ...context }\n }\n\n /**\n * Clear global context\n */\n clearContext(): void {\n this.context = {}\n }\n\n /**\n * Debug log\n */\n debug(message: string, context?: LogContext): void {\n this.log('debug', message, context)\n }\n\n /**\n * Info log\n */\n info(message: string, context?: LogContext): void {\n this.log('info', message, context)\n }\n\n /**\n * Warning log\n */\n warn(message: string, context?: LogContext): void {\n this.log('warn', message, context)\n }\n\n /**\n * Error log\n */\n error(message: string, error?: Error, context?: LogContext): void {\n const errorContext = error\n ? {\n error: {\n name: error.name,\n message: error.message,\n stack: this.config.includeStack ? error.stack : undefined,\n cause: error.cause,\n },\n }\n : {}\n\n this.log('error', message, { ...context, ...errorContext })\n }\n\n /**\n * Fatal log\n */\n fatal(message: string, error?: Error, context?: LogContext): void {\n const errorContext = error\n ? {\n error: {\n name: error.name,\n message: error.message,\n stack: this.config.includeStack ? error.stack : undefined,\n cause: error.cause,\n },\n }\n : {}\n\n this.log('fatal', message, { ...context, ...errorContext })\n }\n\n /**\n * Core logging method\n */\n private log(level: LogLevel, message: string, context?: LogContext): void {\n if (!this.config.enabled) return\n\n if (LOG_LEVELS[level] < LOG_LEVELS[this.config.level]) {\n return\n }\n\n const entry: LogEntry = {\n timestamp: this.config.includeTimestamp ? new Date().toISOString() : '',\n level,\n message,\n context: { ...this.context, ...context },\n }\n\n // Extract error if in context\n if (entry.context?.error) {\n entry.error = entry.context.error as LogEntry['error']\n entry.context.error = undefined\n }\n\n // Call custom handler\n this.config.onLog(entry)\n\n // Call additional handlers (e.g. DB transport)\n for (const handler of this.extraHandlers) {\n handler(entry)\n }\n\n // Output log\n this.output(entry)\n }\n\n /**\n * Output log entry\n */\n private output(entry: LogEntry): void {\n switch (this.config.destination) {\n case 'console':\n this.outputConsole(entry)\n break\n case 'file':\n this.outputFile(entry)\n break\n case 'remote':\n this.outputRemote(entry)\n break\n }\n }\n\n /**\n * Output to console\n */\n private outputConsole(entry: LogEntry): void {\n const output = this.config.pretty ? this.formatPretty(entry) : JSON.stringify(entry)\n\n switch (entry.level) {\n case 'debug':\n console.debug(output)\n break\n case 'info':\n console.info(output)\n break\n case 'warn':\n console.warn(output)\n break\n case 'error':\n case 'fatal':\n console.error(output)\n break\n }\n }\n\n /**\n * Output to file\n */\n private outputFile(entry: LogEntry): void {\n // Would require fs module - placeholder for server-side logging\n console.log(JSON.stringify(entry))\n }\n\n /**\n * Output to remote service\n */\n private async outputRemote(entry: LogEntry): Promise<void> {\n if (!this.config.remoteUrl) return\n\n try {\n await fetch(this.config.remoteUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(entry),\n })\n } catch (error) {\n // Fallback to console if remote fails\n console.error('Failed to send log to remote:', error)\n this.outputConsole(entry)\n }\n }\n\n /**\n * Format log entry for pretty printing\n */\n private formatPretty(entry: LogEntry): string {\n const levelColors: Record<LogLevel, string> = {\n debug: '\\x1b[36m', // Cyan\n info: '\\x1b[32m', // Green\n warn: '\\x1b[33m', // Yellow\n error: '\\x1b[31m', // Red\n fatal: '\\x1b[35m', // Magenta\n }\n\n const reset = '\\x1b[0m'\n const color = levelColors[entry.level]\n\n const parts: string[] = []\n\n if (entry.timestamp) {\n parts.push(`\\x1b[90m${entry.timestamp}${reset}`)\n }\n\n parts.push(`${color}${entry.level.toUpperCase()}${reset}`)\n parts.push(entry.message)\n\n if (entry.context && Object.keys(entry.context).length > 0) {\n parts.push(JSON.stringify(entry.context, null, 2))\n }\n\n if (entry.error) {\n parts.push(`\\n${color}Error: ${entry.error.message}${reset}`)\n if (entry.error.stack) {\n parts.push(entry.error.stack)\n }\n }\n\n return parts.join(' ')\n }\n\n /**\n * Create child logger with additional context\n */\n child(context: LogContext): Logger {\n const childLogger = new Logger(this.config)\n childLogger.setContext({ ...this.context, ...context })\n // Share parent's extra handlers so DB transport applies to child loggers too\n for (const handler of this.extraHandlers) {\n childLogger.addLogHandler(handler)\n }\n return childLogger\n }\n}\n\n/**\n * Default logger instance\n */\nexport const logger = new Logger({\n level: (process.env.LOG_LEVEL as LogLevel) || 'info',\n pretty: process.env.NODE_ENV !== 'production',\n})\n\n/**\n * Create logger with context\n */\nexport function createLogger(context: LogContext): Logger {\n return logger.child(context)\n}\n\n/**\n * Error logger\n */\nexport function logError(error: Error, context?: LogContext): void {\n logger.error(error.message, error, context)\n}\n\n/**\n * Audit logger for security-sensitive operations\n */\nexport function logAudit(action: string, context?: LogContext): void {\n logger.info(`Audit: ${action}`, {\n ...context,\n audit: true,\n action,\n })\n}\n\n/**\n * Database query logger\n */\nexport function logQuery(query: string, duration: number, context?: LogContext): void {\n logger.debug('Database query', {\n ...context,\n query,\n duration,\n })\n\n if (duration > 1000) {\n logger.warn('Slow query detected', {\n ...context,\n query,\n duration,\n })\n }\n}\n"],"mappings":";AA8CA,IAAM,aAAuC;AAAA,EAC3C,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO;AACT;AAEO,IAAM,SAAN,MAAM,QAAO;AAAA,EACV;AAAA,EACA,UAAsB,CAAC;AAAA,EACvB,gBAAkD,CAAC;AAAA,EAE3D,YAAY,SAAuB,CAAC,GAAG;AACrC,SAAK,SAAS;AAAA,MACZ,OAAO,OAAO,SAAS;AAAA,MACvB,SAAS,OAAO,YAAY,SAAY,OAAO,UAAU;AAAA,MACzD,QAAQ,OAAO,WAAW,SAAY,OAAO,SAAS,QAAQ,IAAI,aAAa;AAAA,MAC/E,kBAAkB,OAAO,qBAAqB,SAAY,OAAO,mBAAmB;AAAA,MACpF,cAAc,OAAO,iBAAiB,SAAY,OAAO,eAAe;AAAA,MACxE,aAAa,OAAO,eAAe;AAAA,MACnC,WAAW,OAAO,aAAa;AAAA,MAC/B,OACE,OAAO,UACN,MAAM;AAAA,MAEP;AAAA,IACJ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAc,SAA0C;AACtD,SAAK,cAAc,KAAK,OAAO;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,SAA2B;AACpC,SAAK,UAAU,EAAE,GAAG,KAAK,SAAS,GAAG,QAAQ;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,eAAqB;AACnB,SAAK,UAAU,CAAC;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAiB,SAA4B;AACjD,SAAK,IAAI,SAAS,SAAS,OAAO;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,SAAiB,SAA4B;AAChD,SAAK,IAAI,QAAQ,SAAS,OAAO;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,SAAiB,SAA4B;AAChD,SAAK,IAAI,QAAQ,SAAS,OAAO;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAiB,OAAe,SAA4B;AAChE,UAAM,eAAe,QACjB;AAAA,MACE,OAAO;AAAA,QACL,MAAM,MAAM;AAAA,QACZ,SAAS,MAAM;AAAA,QACf,OAAO,KAAK,OAAO,eAAe,MAAM,QAAQ;AAAA,QAChD,OAAO,MAAM;AAAA,MACf;AAAA,IACF,IACA,CAAC;AAEL,SAAK,IAAI,SAAS,SAAS,EAAE,GAAG,SAAS,GAAG,aAAa,CAAC;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAiB,OAAe,SAA4B;AAChE,UAAM,eAAe,QACjB;AAAA,MACE,OAAO;AAAA,QACL,MAAM,MAAM;AAAA,QACZ,SAAS,MAAM;AAAA,QACf,OAAO,KAAK,OAAO,eAAe,MAAM,QAAQ;AAAA,QAChD,OAAO,MAAM;AAAA,MACf;AAAA,IACF,IACA,CAAC;AAEL,SAAK,IAAI,SAAS,SAAS,EAAE,GAAG,SAAS,GAAG,aAAa,CAAC;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA,EAKQ,IAAI,OAAiB,SAAiB,SAA4B;AACxE,QAAI,CAAC,KAAK,OAAO,QAAS;AAE1B,QAAI,WAAW,KAAK,IAAI,WAAW,KAAK,OAAO,KAAK,GAAG;AACrD;AAAA,IACF;AAEA,UAAM,QAAkB;AAAA,MACtB,WAAW,KAAK,OAAO,oBAAmB,oBAAI,KAAK,GAAE,YAAY,IAAI;AAAA,MACrE;AAAA,MACA;AAAA,MACA,SAAS,EAAE,GAAG,KAAK,SAAS,GAAG,QAAQ;AAAA,IACzC;AAGA,QAAI,MAAM,SAAS,OAAO;AACxB,YAAM,QAAQ,MAAM,QAAQ;AAC5B,YAAM,QAAQ,QAAQ;AAAA,IACxB;AAGA,SAAK,OAAO,MAAM,KAAK;AAGvB,eAAW,WAAW,KAAK,eAAe;AACxC,cAAQ,KAAK;AAAA,IACf;AAGA,SAAK,OAAO,KAAK;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKQ,OAAO,OAAuB;AACpC,YAAQ,KAAK,OAAO,aAAa;AAAA,MAC/B,KAAK;AACH,aAAK,cAAc,KAAK;AACxB;AAAA,MACF,KAAK;AACH,aAAK,WAAW,KAAK;AACrB;AAAA,MACF,KAAK;AACH,aAAK,aAAa,KAAK;AACvB;AAAA,IACJ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,OAAuB;AAC3C,UAAM,SAAS,KAAK,OAAO,SAAS,KAAK,aAAa,KAAK,IAAI,KAAK,UAAU,KAAK;AAEnF,YAAQ,MAAM,OAAO;AAAA,MACnB,KAAK;AACH,gBAAQ,MAAM,MAAM;AACpB;AAAA,MACF,KAAK;AACH,gBAAQ,KAAK,MAAM;AACnB;AAAA,MACF,KAAK;AACH,gBAAQ,KAAK,MAAM;AACnB;AAAA,MACF,KAAK;AAAA,MACL,KAAK;AACH,gBAAQ,MAAM,MAAM;AACpB;AAAA,IACJ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,WAAW,OAAuB;AAExC,YAAQ,IAAI,KAAK,UAAU,KAAK,CAAC;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,aAAa,OAAgC;AACzD,QAAI,CAAC,KAAK,OAAO,UAAW;AAE5B,QAAI;AACF,YAAM,MAAM,KAAK,OAAO,WAAW;AAAA,QACjC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU,KAAK;AAAA,MAC5B,CAAC;AAAA,IACH,SAAS,OAAO;AAEd,cAAQ,MAAM,iCAAiC,KAAK;AACpD,WAAK,cAAc,KAAK;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAa,OAAyB;AAC5C,UAAM,cAAwC;AAAA,MAC5C,OAAO;AAAA;AAAA,MACP,MAAM;AAAA;AAAA,MACN,MAAM;AAAA;AAAA,MACN,OAAO;AAAA;AAAA,MACP,OAAO;AAAA;AAAA,IACT;AAEA,UAAM,QAAQ;AACd,UAAM,QAAQ,YAAY,MAAM,KAAK;AAErC,UAAM,QAAkB,CAAC;AAEzB,QAAI,MAAM,WAAW;AACnB,YAAM,KAAK,WAAW,MAAM,SAAS,GAAG,KAAK,EAAE;AAAA,IACjD;AAEA,UAAM,KAAK,GAAG,KAAK,GAAG,MAAM,MAAM,YAAY,CAAC,GAAG,KAAK,EAAE;AACzD,UAAM,KAAK,MAAM,OAAO;AAExB,QAAI,MAAM,WAAW,OAAO,KAAK,MAAM,OAAO,EAAE,SAAS,GAAG;AAC1D,YAAM,KAAK,KAAK,UAAU,MAAM,SAAS,MAAM,CAAC,CAAC;AAAA,IACnD;AAEA,QAAI,MAAM,OAAO;AACf,YAAM,KAAK;AAAA,EAAK,KAAK,UAAU,MAAM,MAAM,OAAO,GAAG,KAAK,EAAE;AAC5D,UAAI,MAAM,MAAM,OAAO;AACrB,cAAM,KAAK,MAAM,MAAM,KAAK;AAAA,MAC9B;AAAA,IACF;AAEA,WAAO,MAAM,KAAK,GAAG;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAA6B;AACjC,UAAM,cAAc,IAAI,QAAO,KAAK,MAAM;AAC1C,gBAAY,WAAW,EAAE,GAAG,KAAK,SAAS,GAAG,QAAQ,CAAC;AAEtD,eAAW,WAAW,KAAK,eAAe;AACxC,kBAAY,cAAc,OAAO;AAAA,IACnC;AACA,WAAO;AAAA,EACT;AACF;AAKO,IAAM,SAAS,IAAI,OAAO;AAAA,EAC/B,OAAQ,QAAQ,IAAI,aAA0B;AAAA,EAC9C,QAAQ,QAAQ,IAAI,aAAa;AACnC,CAAC;AAKM,SAAS,aAAa,SAA6B;AACxD,SAAO,OAAO,MAAM,OAAO;AAC7B;AAKO,SAAS,SAAS,OAAc,SAA4B;AACjE,SAAO,MAAM,MAAM,SAAS,OAAO,OAAO;AAC5C;AAKO,SAAS,SAAS,QAAgB,SAA4B;AACnE,SAAO,KAAK,UAAU,MAAM,IAAI;AAAA,IAC9B,GAAG;AAAA,IACH,OAAO;AAAA,IACP;AAAA,EACF,CAAC;AACH;AAKO,SAAS,SAAS,OAAe,UAAkB,SAA4B;AACpF,SAAO,MAAM,kBAAkB;AAAA,IAC7B,GAAG;AAAA,IACH;AAAA,IACA;AAAA,EACF,CAAC;AAED,MAAI,WAAW,KAAM;AACnB,WAAO,KAAK,uBAAuB;AAAA,MACjC,GAAG;AAAA,MACH;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AACF;","names":[]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// src/validation/password-schema.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var passwordSchema = z.string().min(8, "Password must be at least 8 characters").max(128, "Password is too long").regex(/[A-Z]/, "Password must contain at least one uppercase letter").regex(/[a-z]/, "Password must contain at least one lowercase letter").regex(/[0-9]/, "Password must contain at least one number");
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
passwordSchema
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=chunk-UEYUNTMY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/validation/password-schema.ts"],"sourcesContent":["import { z } from 'zod'\n\n/**\n * Password validation schema\n *\n * Requirements:\n * - Minimum 8 characters\n * - Maximum 128 characters\n * - At least one uppercase letter\n * - At least one lowercase letter\n * - At least one number\n */\nexport const passwordSchema = z\n .string()\n .min(8, 'Password must be at least 8 characters')\n .max(128, 'Password is too long')\n .regex(/[A-Z]/, 'Password must contain at least one uppercase letter')\n .regex(/[a-z]/, 'Password must contain at least one lowercase letter')\n .regex(/[0-9]/, 'Password must contain at least one number')\n\nexport type Password = z.infer<typeof passwordSchema>\n"],"mappings":";AAAA,SAAS,SAAS;AAYX,IAAM,iBAAiB,EAC3B,OAAO,EACP,IAAI,GAAG,wCAAwC,EAC/C,IAAI,KAAK,sBAAsB,EAC/B,MAAM,SAAS,qDAAqD,EACpE,MAAM,SAAS,qDAAqD,EACpE,MAAM,SAAS,2CAA2C;","names":[]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSL Configuration Utility
|
|
3
|
+
*
|
|
4
|
+
* Provides centralized SSL configuration for PostgreSQL connections based on
|
|
5
|
+
* connection string sslmode parameter and environment variables.
|
|
6
|
+
*
|
|
7
|
+
* Extracted from @revealui/core to break circular dependencies
|
|
8
|
+
*
|
|
9
|
+
* @module ssl-config
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* PostgreSQL SSL configuration options
|
|
13
|
+
*/
|
|
14
|
+
interface SSLConfig {
|
|
15
|
+
rejectUnauthorized: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Determines the appropriate SSL configuration for a PostgreSQL connection
|
|
19
|
+
* based on the connection string's sslmode parameter.
|
|
20
|
+
*
|
|
21
|
+
* SSL Modes (aligned with PostgreSQL libpq standards):
|
|
22
|
+
* - `disable`: No SSL connection
|
|
23
|
+
* - `require`: SSL connection with certificate verification
|
|
24
|
+
* - `verify-full`: Full SSL verification (same as require in pg v9+)
|
|
25
|
+
* - `verify-ca`: CA verification (treated as verify-full)
|
|
26
|
+
*
|
|
27
|
+
* Environment Override:
|
|
28
|
+
* - `DATABASE_SSL_REJECT_UNAUTHORIZED=false`: Force skip certificate verification
|
|
29
|
+
* (DEVELOPMENT ONLY - use for self-signed certificates in local environments)
|
|
30
|
+
*
|
|
31
|
+
* @param connectionString - PostgreSQL connection string (may include sslmode parameter)
|
|
32
|
+
* @returns SSL configuration object or false to disable SSL
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* // Connection string with SSL required
|
|
37
|
+
* const ssl = getSSLConfig('postgresql://user:pass@host/db?sslmode=require')
|
|
38
|
+
* // Returns: { rejectUnauthorized: true }
|
|
39
|
+
*
|
|
40
|
+
* // Connection string without SSL
|
|
41
|
+
* const ssl = getSSLConfig('postgresql://localhost:5432/db')
|
|
42
|
+
* // Returns: false
|
|
43
|
+
*
|
|
44
|
+
* // Development override for self-signed certificates
|
|
45
|
+
* process.env.DATABASE_SSL_REJECT_UNAUTHORIZED = 'false'
|
|
46
|
+
* const ssl = getSSLConfig('postgresql://user:pass@host/db?sslmode=require')
|
|
47
|
+
* // Returns: { rejectUnauthorized: false }
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
declare function getSSLConfig(connectionString: string): SSLConfig | false;
|
|
51
|
+
/**
|
|
52
|
+
* Validates SSL configuration for production environments.
|
|
53
|
+
* Warns if insecure SSL settings are detected in production.
|
|
54
|
+
*
|
|
55
|
+
* @param connectionString - PostgreSQL connection string
|
|
56
|
+
* @param environment - Current environment (e.g., 'production', 'development')
|
|
57
|
+
*/
|
|
58
|
+
declare function validateSSLConfig(connectionString: string, environment?: string): boolean;
|
|
59
|
+
|
|
60
|
+
export { type SSLConfig, getSSLConfig, validateSSLConfig };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { SSLConfig, getSSLConfig, validateSSLConfig } from './database/index.js';
|
|
2
|
+
export { LogContext, LogEntry, LogLevel, Logger, LoggerConfig, createLogger, logAudit, logError, logQuery, logger } from './logger/index.js';
|
|
3
|
+
export { Password, passwordSchema } from './validation/index.js';
|
|
4
|
+
import 'zod';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getSSLConfig,
|
|
3
|
+
validateSSLConfig
|
|
4
|
+
} from "./chunk-KUMOGLHP.js";
|
|
5
|
+
import {
|
|
6
|
+
Logger,
|
|
7
|
+
createLogger,
|
|
8
|
+
logAudit,
|
|
9
|
+
logError,
|
|
10
|
+
logQuery,
|
|
11
|
+
logger
|
|
12
|
+
} from "./chunk-QR4YAGWO.js";
|
|
13
|
+
import {
|
|
14
|
+
passwordSchema
|
|
15
|
+
} from "./chunk-UEYUNTMY.js";
|
|
16
|
+
export {
|
|
17
|
+
Logger,
|
|
18
|
+
createLogger,
|
|
19
|
+
getSSLConfig,
|
|
20
|
+
logAudit,
|
|
21
|
+
logError,
|
|
22
|
+
logQuery,
|
|
23
|
+
logger,
|
|
24
|
+
passwordSchema,
|
|
25
|
+
validateSSLConfig
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured Logging Infrastructure
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent, structured logging across the application
|
|
5
|
+
* Extracted from @revealui/core to break circular dependencies
|
|
6
|
+
*/
|
|
7
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
8
|
+
interface LogContext {
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
userId?: string;
|
|
11
|
+
requestId?: string;
|
|
12
|
+
sessionId?: string;
|
|
13
|
+
traceId?: string;
|
|
14
|
+
spanId?: string;
|
|
15
|
+
}
|
|
16
|
+
interface LogEntry {
|
|
17
|
+
timestamp: string;
|
|
18
|
+
level: LogLevel;
|
|
19
|
+
message: string;
|
|
20
|
+
context?: LogContext;
|
|
21
|
+
error?: {
|
|
22
|
+
name: string;
|
|
23
|
+
message: string;
|
|
24
|
+
stack?: string;
|
|
25
|
+
cause?: unknown;
|
|
26
|
+
};
|
|
27
|
+
metadata?: Record<string, unknown>;
|
|
28
|
+
}
|
|
29
|
+
interface LoggerConfig {
|
|
30
|
+
level?: LogLevel;
|
|
31
|
+
enabled?: boolean;
|
|
32
|
+
pretty?: boolean;
|
|
33
|
+
includeTimestamp?: boolean;
|
|
34
|
+
includeStack?: boolean;
|
|
35
|
+
destination?: 'console' | 'file' | 'remote';
|
|
36
|
+
remoteUrl?: string;
|
|
37
|
+
onLog?: (entry: LogEntry) => void;
|
|
38
|
+
}
|
|
39
|
+
declare class Logger {
|
|
40
|
+
private config;
|
|
41
|
+
private context;
|
|
42
|
+
private extraHandlers;
|
|
43
|
+
constructor(config?: LoggerConfig);
|
|
44
|
+
/**
|
|
45
|
+
* Register an additional log handler (e.g. DB transport).
|
|
46
|
+
* Called after every log entry, fire-and-forget. Must not throw.
|
|
47
|
+
*/
|
|
48
|
+
addLogHandler(handler: (entry: LogEntry) => void): void;
|
|
49
|
+
/**
|
|
50
|
+
* Set global context
|
|
51
|
+
*/
|
|
52
|
+
setContext(context: LogContext): void;
|
|
53
|
+
/**
|
|
54
|
+
* Clear global context
|
|
55
|
+
*/
|
|
56
|
+
clearContext(): void;
|
|
57
|
+
/**
|
|
58
|
+
* Debug log
|
|
59
|
+
*/
|
|
60
|
+
debug(message: string, context?: LogContext): void;
|
|
61
|
+
/**
|
|
62
|
+
* Info log
|
|
63
|
+
*/
|
|
64
|
+
info(message: string, context?: LogContext): void;
|
|
65
|
+
/**
|
|
66
|
+
* Warning log
|
|
67
|
+
*/
|
|
68
|
+
warn(message: string, context?: LogContext): void;
|
|
69
|
+
/**
|
|
70
|
+
* Error log
|
|
71
|
+
*/
|
|
72
|
+
error(message: string, error?: Error, context?: LogContext): void;
|
|
73
|
+
/**
|
|
74
|
+
* Fatal log
|
|
75
|
+
*/
|
|
76
|
+
fatal(message: string, error?: Error, context?: LogContext): void;
|
|
77
|
+
/**
|
|
78
|
+
* Core logging method
|
|
79
|
+
*/
|
|
80
|
+
private log;
|
|
81
|
+
/**
|
|
82
|
+
* Output log entry
|
|
83
|
+
*/
|
|
84
|
+
private output;
|
|
85
|
+
/**
|
|
86
|
+
* Output to console
|
|
87
|
+
*/
|
|
88
|
+
private outputConsole;
|
|
89
|
+
/**
|
|
90
|
+
* Output to file
|
|
91
|
+
*/
|
|
92
|
+
private outputFile;
|
|
93
|
+
/**
|
|
94
|
+
* Output to remote service
|
|
95
|
+
*/
|
|
96
|
+
private outputRemote;
|
|
97
|
+
/**
|
|
98
|
+
* Format log entry for pretty printing
|
|
99
|
+
*/
|
|
100
|
+
private formatPretty;
|
|
101
|
+
/**
|
|
102
|
+
* Create child logger with additional context
|
|
103
|
+
*/
|
|
104
|
+
child(context: LogContext): Logger;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Default logger instance
|
|
108
|
+
*/
|
|
109
|
+
declare const logger: Logger;
|
|
110
|
+
/**
|
|
111
|
+
* Create logger with context
|
|
112
|
+
*/
|
|
113
|
+
declare function createLogger(context: LogContext): Logger;
|
|
114
|
+
/**
|
|
115
|
+
* Error logger
|
|
116
|
+
*/
|
|
117
|
+
declare function logError(error: Error, context?: LogContext): void;
|
|
118
|
+
/**
|
|
119
|
+
* Audit logger for security-sensitive operations
|
|
120
|
+
*/
|
|
121
|
+
declare function logAudit(action: string, context?: LogContext): void;
|
|
122
|
+
/**
|
|
123
|
+
* Database query logger
|
|
124
|
+
*/
|
|
125
|
+
declare function logQuery(query: string, duration: number, context?: LogContext): void;
|
|
126
|
+
|
|
127
|
+
export { type LogContext, type LogEntry, type LogLevel, Logger, type LoggerConfig, createLogger, logAudit, logError, logQuery, logger };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Password validation schema
|
|
5
|
+
*
|
|
6
|
+
* Requirements:
|
|
7
|
+
* - Minimum 8 characters
|
|
8
|
+
* - Maximum 128 characters
|
|
9
|
+
* - At least one uppercase letter
|
|
10
|
+
* - At least one lowercase letter
|
|
11
|
+
* - At least one number
|
|
12
|
+
*/
|
|
13
|
+
declare const passwordSchema: z.ZodString;
|
|
14
|
+
type Password = z.infer<typeof passwordSchema>;
|
|
15
|
+
|
|
16
|
+
export { type Password, passwordSchema };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@revealui/utils",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Shared utilities for RevealUI - logger, SSL config, and common helpers",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./logger": {
|
|
13
|
+
"types": "./dist/logger/index.d.ts",
|
|
14
|
+
"import": "./dist/logger/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./database": {
|
|
17
|
+
"types": "./dist/database/index.d.ts",
|
|
18
|
+
"import": "./dist/database/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./validation": {
|
|
21
|
+
"types": "./dist/validation/index.d.ts",
|
|
22
|
+
"import": "./dist/validation/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist"
|
|
27
|
+
],
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public",
|
|
30
|
+
"registry": "https://registry.npmjs.org"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"zod": "^4.3.6"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/node": "^25.3.0",
|
|
37
|
+
"tsup": "^8.5.1",
|
|
38
|
+
"typescript": "^5.9.3",
|
|
39
|
+
"vitest": "^4.0.18",
|
|
40
|
+
"dev": "0.0.1"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsup",
|
|
44
|
+
"dev": "tsup --watch",
|
|
45
|
+
"typecheck": "tsc --noEmit",
|
|
46
|
+
"test": "vitest run --passWithNoTests",
|
|
47
|
+
"test:watch": "vitest",
|
|
48
|
+
"lint": "biome check .",
|
|
49
|
+
"lint:fix": "biome check --write .",
|
|
50
|
+
"clean": "rm -rf dist"
|
|
51
|
+
}
|
|
52
|
+
}
|