vibe-gx 4.1.4 → 4.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/package.json +1 -1
- package/utils/core/logger.js +41 -26
- package/utils/core/parser.js +13 -7
- package/utils/core/response.js +6 -1
- package/utils/core/server.js +8 -2
- package/vibe.d.ts +78 -16
- package/vibe.js +7 -3
package/package.json
CHANGED
package/utils/core/logger.js
CHANGED
|
@@ -9,6 +9,7 @@ const LOG_LEVELS = {
|
|
|
9
9
|
warn: 40,
|
|
10
10
|
error: 50,
|
|
11
11
|
fatal: 60,
|
|
12
|
+
silent: 100, // Higher than all levels — suppresses all output (logger: false)
|
|
12
13
|
};
|
|
13
14
|
|
|
14
15
|
const LEVEL_NAMES = {
|
|
@@ -136,45 +137,59 @@ export class Logger {
|
|
|
136
137
|
_printPretty(log) {
|
|
137
138
|
const time = new Date(log.time).toLocaleTimeString();
|
|
138
139
|
const lvlName = LEVEL_NAMES[log.level] || "INFO";
|
|
139
|
-
let prefixC = color.cyan;
|
|
140
|
-
if (log.level >= 50) prefixC = color.red;
|
|
141
|
-
else if (log.level === 40) prefixC = color.yellow;
|
|
142
|
-
else if (log.level <= 20) prefixC = color.dim;
|
|
143
|
-
|
|
144
|
-
const prefix = prefixC(`[VIBE ${lvlName} ${time}]`);
|
|
145
|
-
let context = "";
|
|
146
|
-
if (log.reqId) {
|
|
147
|
-
context = `\x1b[90m[${log.reqId}]\x1b[0m `;
|
|
148
|
-
}
|
|
149
140
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
141
|
+
const isError = log.level >= 50;
|
|
142
|
+
const isWarn = log.level === 40;
|
|
143
|
+
const isDebug = log.level <= 20;
|
|
144
|
+
|
|
145
|
+
// Build context tag (reqId)
|
|
146
|
+
const context = log.reqId ? `[${log.reqId}] ` : "";
|
|
154
147
|
|
|
148
|
+
// Build message content
|
|
149
|
+
let content = log.msg || "";
|
|
155
150
|
if (log.err && log.err.stack) {
|
|
156
|
-
content += "\n" +
|
|
151
|
+
content += "\n" + log.err.stack;
|
|
157
152
|
}
|
|
158
153
|
|
|
159
|
-
//
|
|
154
|
+
// Build metadata string (skip standard keys)
|
|
160
155
|
const skipKeys = [
|
|
161
|
-
"level",
|
|
162
|
-
"time",
|
|
163
|
-
"pid",
|
|
164
|
-
"hostname",
|
|
165
|
-
"reqId",
|
|
166
|
-
"msg",
|
|
167
|
-
"err",
|
|
168
|
-
"color",
|
|
156
|
+
"level", "time", "pid", "hostname", "reqId", "msg", "err", "color",
|
|
169
157
|
];
|
|
170
158
|
let metaStr = "";
|
|
171
159
|
for (const key of Object.keys(log)) {
|
|
172
160
|
if (!skipKeys.includes(key)) {
|
|
173
|
-
metaStr += `
|
|
161
|
+
metaStr += ` ${key}=${JSON.stringify(log[key])}`;
|
|
174
162
|
}
|
|
175
163
|
}
|
|
176
164
|
|
|
177
|
-
|
|
165
|
+
const rawPrefix = `[VIBE ${lvlName} ${time}]`;
|
|
166
|
+
|
|
167
|
+
if (isError) {
|
|
168
|
+
// Entire line is red — prefix, context, message, stack, metadata
|
|
169
|
+
const fullLine = `${rawPrefix} ${context}${content}${metaStr}`;
|
|
170
|
+
this.stream.write(color.red(fullLine) + "\n");
|
|
171
|
+
} else if (isWarn) {
|
|
172
|
+
// Yellow prefix, bright content
|
|
173
|
+
const coloredContent = log.color && color[log.color]
|
|
174
|
+
? color[log.color](content)
|
|
175
|
+
: color.bright(content);
|
|
176
|
+
this.stream.write(
|
|
177
|
+
color.yellow(rawPrefix) + " " + context + coloredContent +
|
|
178
|
+
(metaStr ? color.dim(metaStr) : "") + "\n",
|
|
179
|
+
);
|
|
180
|
+
} else if (isDebug) {
|
|
181
|
+
// Dim entire line for trace/debug
|
|
182
|
+
this.stream.write(color.dim(`${rawPrefix} ${context}${content}${metaStr}`) + "\n");
|
|
183
|
+
} else {
|
|
184
|
+
// Info — green prefix + bright content (matches [VIBE LOG] style)
|
|
185
|
+
const coloredContent = log.color && color[log.color]
|
|
186
|
+
? color[log.color](content)
|
|
187
|
+
: color.bright(content);
|
|
188
|
+
this.stream.write(
|
|
189
|
+
color.green(rawPrefix) + " " + context + coloredContent +
|
|
190
|
+
(metaStr ? color.dim(metaStr) : "") + "\n",
|
|
191
|
+
);
|
|
192
|
+
}
|
|
178
193
|
}
|
|
179
194
|
}
|
|
180
195
|
|
package/utils/core/parser.js
CHANGED
|
@@ -103,7 +103,7 @@ function parseMultipart(req, res, media, options, resolve, reject) {
|
|
|
103
103
|
},
|
|
104
104
|
});
|
|
105
105
|
} catch (err) {
|
|
106
|
-
|
|
106
|
+
options.logger?.error(err, "[VIBE] Busboy init failed");
|
|
107
107
|
return resolve();
|
|
108
108
|
}
|
|
109
109
|
|
|
@@ -152,7 +152,10 @@ function parseMultipart(req, res, media, options, resolve, reject) {
|
|
|
152
152
|
media.public &&
|
|
153
153
|
!dest.startsWith(path.resolve(options.publicFolder || ""))
|
|
154
154
|
) {
|
|
155
|
-
|
|
155
|
+
options.logger?.warn(
|
|
156
|
+
{ dest, publicFolder: options.publicFolder },
|
|
157
|
+
"[VIBE] Attempted upload outside public folder, skipping",
|
|
158
|
+
);
|
|
156
159
|
pendingWrites--;
|
|
157
160
|
checkComplete();
|
|
158
161
|
return file.resume();
|
|
@@ -161,7 +164,7 @@ function parseMultipart(req, res, media, options, resolve, reject) {
|
|
|
161
164
|
try {
|
|
162
165
|
if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
|
|
163
166
|
} catch (err) {
|
|
164
|
-
|
|
167
|
+
options.logger?.error(err, "[VIBE] Failed to create upload folder");
|
|
165
168
|
pendingWrites--;
|
|
166
169
|
checkComplete();
|
|
167
170
|
return file.resume();
|
|
@@ -200,14 +203,14 @@ function parseMultipart(req, res, media, options, resolve, reject) {
|
|
|
200
203
|
});
|
|
201
204
|
|
|
202
205
|
file.on("error", (err) => {
|
|
203
|
-
|
|
206
|
+
options.logger?.error(err, "[VIBE] File stream error");
|
|
204
207
|
writeStream.end();
|
|
205
208
|
pendingWrites--;
|
|
206
209
|
checkComplete();
|
|
207
210
|
});
|
|
208
211
|
|
|
209
212
|
writeStream.on("error", (err) => {
|
|
210
|
-
|
|
213
|
+
options.logger?.error(err, "[VIBE] Write stream error");
|
|
211
214
|
file.resume();
|
|
212
215
|
pendingWrites--;
|
|
213
216
|
checkComplete();
|
|
@@ -231,7 +234,7 @@ function parseMultipart(req, res, media, options, resolve, reject) {
|
|
|
231
234
|
});
|
|
232
235
|
|
|
233
236
|
bb.on("error", (err) => {
|
|
234
|
-
|
|
237
|
+
options.logger?.error(err, "[VIBE] Busboy error");
|
|
235
238
|
req.unpipe(bb);
|
|
236
239
|
reject(err);
|
|
237
240
|
});
|
|
@@ -266,7 +269,10 @@ function parseJson(req, res, media, options, resolve, reject) {
|
|
|
266
269
|
req.on("data", (chunk) => {
|
|
267
270
|
body += chunk;
|
|
268
271
|
if (body.length > limit) {
|
|
269
|
-
|
|
272
|
+
options.logger?.warn(
|
|
273
|
+
{ limit, received: body.length },
|
|
274
|
+
"[VIBE] JSON payload too large, destroying connection",
|
|
275
|
+
);
|
|
270
276
|
req.destroy();
|
|
271
277
|
}
|
|
272
278
|
});
|
package/utils/core/response.js
CHANGED
|
@@ -243,7 +243,12 @@ const vibeResponseMethods = {
|
|
|
243
243
|
* @param {Error} error
|
|
244
244
|
*/
|
|
245
245
|
serverError(error) {
|
|
246
|
-
|
|
246
|
+
const logger = this._vibeOptions?.logger;
|
|
247
|
+
if (logger) {
|
|
248
|
+
logger.error(error, "[VIBE] Internal server error");
|
|
249
|
+
} else {
|
|
250
|
+
console.error(error);
|
|
251
|
+
}
|
|
247
252
|
this.writeHead(500, JSON_CT);
|
|
248
253
|
this.end(RESPONSES.serverError);
|
|
249
254
|
},
|
package/utils/core/server.js
CHANGED
|
@@ -319,8 +319,14 @@ async function server(options, port, host, callback) {
|
|
|
319
319
|
getNetworkIP(mainHost, port);
|
|
320
320
|
|
|
321
321
|
const strategy = useTrieMatching ? "Trie (O(log n))" : "Linear (O(n))";
|
|
322
|
-
|
|
323
|
-
|
|
322
|
+
options.logger.info(
|
|
323
|
+
{
|
|
324
|
+
strategy,
|
|
325
|
+
routeCount: options.routeCount,
|
|
326
|
+
staticRoutes: staticRoutes.size,
|
|
327
|
+
trieThreshold: options.trieThreshold,
|
|
328
|
+
},
|
|
329
|
+
"[VIBE] Route matching strategy initialized",
|
|
324
330
|
);
|
|
325
331
|
|
|
326
332
|
if (callback) callback();
|
package/vibe.d.ts
CHANGED
|
@@ -237,10 +237,8 @@ export interface VibeRequest extends IncomingMessage {
|
|
|
237
237
|
body: Record<string, any>;
|
|
238
238
|
/** Uploaded files array (if multipart/form-data) */
|
|
239
239
|
files?: UploadedFile[];
|
|
240
|
-
/**
|
|
240
|
+
/** Real client IP — first entry from x-forwarded-for, x-real-ip, or socket address */
|
|
241
241
|
ip?: string;
|
|
242
|
-
/** Detailed client IP info */
|
|
243
|
-
fullIp?: string;
|
|
244
242
|
/** Automatically generated UUID for the request lifecycle */
|
|
245
243
|
id: string;
|
|
246
244
|
/** Context-bound logger automatically stamped with the req.id constraint */
|
|
@@ -302,9 +300,58 @@ export type Interceptor = (
|
|
|
302
300
|
res: VibeResponse,
|
|
303
301
|
) => boolean | void | Promise<boolean | void>;
|
|
304
302
|
|
|
303
|
+
/**
|
|
304
|
+
* Scoped app interface passed to register() plugin callbacks.
|
|
305
|
+
* A subset of VibeApp — excludes server-level methods that make no sense
|
|
306
|
+
* inside an encapsulated plugin (listen, logRoutes, setPublicFolder, include).
|
|
307
|
+
*/
|
|
308
|
+
export interface ScopedVibeApp {
|
|
309
|
+
get: RouteRegistrar;
|
|
310
|
+
post: RouteRegistrar;
|
|
311
|
+
put: RouteRegistrar;
|
|
312
|
+
del: RouteRegistrar;
|
|
313
|
+
patch: RouteRegistrar;
|
|
314
|
+
head: RouteRegistrar;
|
|
315
|
+
|
|
316
|
+
/** Register a global interceptor within this plugin scope */
|
|
317
|
+
plugin: (interceptor: Interceptor) => void;
|
|
318
|
+
|
|
319
|
+
/** Register a nested plugin */
|
|
320
|
+
register: (fn: PluginCallback, opts?: RegisterOptions) => Promise<void>;
|
|
321
|
+
|
|
322
|
+
/** Decorate the app with a custom property */
|
|
323
|
+
decorate: (name: string, value: any) => void;
|
|
324
|
+
|
|
325
|
+
/** Decorate request objects with a custom property */
|
|
326
|
+
decorateRequest: (name: string, value: any) => void;
|
|
327
|
+
|
|
328
|
+
/** Decorate response objects with a custom property */
|
|
329
|
+
decorateReply: (name: string, value: any) => void;
|
|
330
|
+
|
|
331
|
+
/** Override the error handler for this plugin scope */
|
|
332
|
+
setErrorHandler: (
|
|
333
|
+
fn: (error: Error, req: VibeRequest, res: VibeResponse) => void,
|
|
334
|
+
) => void;
|
|
335
|
+
|
|
336
|
+
/** Structured logger — app.log.info(), .warn(), .error() etc. */
|
|
337
|
+
log: LoggerAPI;
|
|
338
|
+
|
|
339
|
+
/** Alias for log */
|
|
340
|
+
logger: LoggerAPI;
|
|
341
|
+
|
|
342
|
+
/** Legacy colorized string logger */
|
|
343
|
+
logLegacy: (
|
|
344
|
+
value: any,
|
|
345
|
+
typeOrColor?: ColorName | "info" | "error" | "warn" | "req",
|
|
346
|
+
) => void;
|
|
347
|
+
|
|
348
|
+
/** Any decorators registered via decorate() are available as direct properties */
|
|
349
|
+
[key: string]: any;
|
|
350
|
+
}
|
|
351
|
+
|
|
305
352
|
/** Plugin callback function (Fastify-style) */
|
|
306
353
|
export type PluginCallback = (
|
|
307
|
-
app:
|
|
354
|
+
app: ScopedVibeApp,
|
|
308
355
|
opts: RegisterOptions,
|
|
309
356
|
) => void | Promise<void>;
|
|
310
357
|
|
|
@@ -391,11 +438,23 @@ export interface RouterAPI {
|
|
|
391
438
|
head: RouteRegistrar;
|
|
392
439
|
|
|
393
440
|
/**
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
* @
|
|
441
|
+
* Pino/Fastify-compatible structured logger.
|
|
442
|
+
* Available inside both `app.register()` plugins and `app.include()` sub-routers.
|
|
443
|
+
* @example
|
|
444
|
+
* api.log.info("Route registered");
|
|
445
|
+
* api.log.warn({ userId: 1 }, "Slow query");
|
|
446
|
+
*/
|
|
447
|
+
log: LoggerAPI;
|
|
448
|
+
|
|
449
|
+
/** Alias for `log` — consistent with `app.logger` */
|
|
450
|
+
logger: LoggerAPI;
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Legacy colorized string logger (plain terminal output).
|
|
454
|
+
* @param value The message to log
|
|
455
|
+
* @param typeOrColor Optional color name (e.g. 'green', 'red')
|
|
397
456
|
*/
|
|
398
|
-
|
|
457
|
+
logLegacy: (
|
|
399
458
|
value: any,
|
|
400
459
|
typeOrColor?: ColorName | "info" | "error" | "warn" | "req",
|
|
401
460
|
) => void;
|
|
@@ -487,6 +546,17 @@ export interface VibeApp extends RouterAPI {
|
|
|
487
546
|
|
|
488
547
|
/** Alias for `app.log` */
|
|
489
548
|
logger: LoggerAPI;
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Legacy colorized string logger (plain terminal output).
|
|
552
|
+
* Bypasses the Pino JSON interface — for simple dev-time messages.
|
|
553
|
+
* @param value The message to log
|
|
554
|
+
* @param typeOrColor Optional color name (e.g. 'green', 'red')
|
|
555
|
+
*/
|
|
556
|
+
logLegacy: (
|
|
557
|
+
value: any,
|
|
558
|
+
typeOrColor?: ColorName | "info" | "error" | "warn" | "req",
|
|
559
|
+
) => void;
|
|
490
560
|
}
|
|
491
561
|
|
|
492
562
|
/**
|
|
@@ -759,11 +829,3 @@ export function adapt(
|
|
|
759
829
|
mw: (req: any, res: any, next: (err?: any) => void) => void,
|
|
760
830
|
): Interceptor;
|
|
761
831
|
|
|
762
|
-
/**
|
|
763
|
-
* Adapt multiple Express middlewares at once.
|
|
764
|
-
* @param middlewares - Express middleware functions
|
|
765
|
-
* @returns Array of Vibe-compatible interceptors
|
|
766
|
-
*/
|
|
767
|
-
export function adaptAll(
|
|
768
|
-
...middlewares: Array<(req: any, res: any, next: (err?: any) => void) => void>
|
|
769
|
-
): Interceptor[];
|
package/vibe.js
CHANGED
|
@@ -37,7 +37,6 @@ function pathToRegex(path) {
|
|
|
37
37
|
* size: number
|
|
38
38
|
* }>,
|
|
39
39
|
* ip?: string,
|
|
40
|
-
* fullIp?: string
|
|
41
40
|
* }} VibeRequest
|
|
42
41
|
*/
|
|
43
42
|
|
|
@@ -430,7 +429,10 @@ const vibe = (config = {}) => {
|
|
|
430
429
|
decorateRequest,
|
|
431
430
|
decorateReply,
|
|
432
431
|
register,
|
|
433
|
-
log,
|
|
432
|
+
log: appLogger, // Structured logger (api.log.info / warn / error etc.)
|
|
433
|
+
logger: appLogger, // Alias — consistent with root app.logger
|
|
434
|
+
logLegacy: log, // Legacy colorized string logger (api.logLegacy(msg, color))
|
|
435
|
+
setErrorHandler: (fn) => { options.errorHandler = fn; },
|
|
434
436
|
// Expose decorators
|
|
435
437
|
...options.decorators,
|
|
436
438
|
};
|
|
@@ -486,7 +488,9 @@ const vibe = (config = {}) => {
|
|
|
486
488
|
del: wrap("DELETE"),
|
|
487
489
|
patch: wrap("PATCH"),
|
|
488
490
|
head: wrap("HEAD"),
|
|
489
|
-
log,
|
|
491
|
+
log: appLogger, // Structured logger — consistent with app.log
|
|
492
|
+
logger: appLogger, // Alias
|
|
493
|
+
logLegacy: log, // Legacy colorized string logger
|
|
490
494
|
plugin,
|
|
491
495
|
};
|
|
492
496
|
}
|