cipher-logger 0.1.2 → 0.1.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/README.md +83 -0
- package/dist/index.d.mts +17 -3
- package/dist/index.d.ts +17 -3
- package/dist/index.js +154 -0
- package/dist/index.mjs +151 -0
- package/package.json +26 -2
package/README.md
CHANGED
|
@@ -39,6 +39,10 @@
|
|
|
39
39
|
- **Express middleware** — records real `status` and `duration` after the response finishes
|
|
40
40
|
- **Next.js middleware** — drop-in support for `middleware.ts`
|
|
41
41
|
- **Zero heavy dependencies** — only `express` or `next` as optional peer dependencies
|
|
42
|
+
- **Fastify middleware** — lightweight hook-compatible middleware for Fastify
|
|
43
|
+
- **NestJS middleware** — Express-compatible middleware for Nest apps
|
|
44
|
+
- **Hono middleware** — edge-friendly middleware for Hono apps
|
|
45
|
+
- **Zero heavy dependencies** — only framework peers are optional
|
|
42
46
|
- **Node.js 18+** compatible
|
|
43
47
|
|
|
44
48
|
---
|
|
@@ -63,6 +67,15 @@ npm install express
|
|
|
63
67
|
|
|
64
68
|
# Next.js
|
|
65
69
|
npm install next
|
|
70
|
+
|
|
71
|
+
# Fastify
|
|
72
|
+
npm install fastify
|
|
73
|
+
|
|
74
|
+
# NestJS (core packages)
|
|
75
|
+
npm install @nestjs/core @nestjs/common
|
|
76
|
+
|
|
77
|
+
# Hono
|
|
78
|
+
npm install hono
|
|
66
79
|
```
|
|
67
80
|
|
|
68
81
|
---
|
|
@@ -222,6 +235,73 @@ export const config = {
|
|
|
222
235
|
|
|
223
236
|
---
|
|
224
237
|
|
|
238
|
+
## Fastify
|
|
239
|
+
|
|
240
|
+
Register the Fastify-compatible middleware returned by `cipher.fastify()` using `addHook`:
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
import fastify from "fastify";
|
|
244
|
+
import { createCipherLogger } from "cipher-logger";
|
|
245
|
+
|
|
246
|
+
const app = fastify();
|
|
247
|
+
|
|
248
|
+
const cipher = createCipherLogger({
|
|
249
|
+
fields: { ip: true, userAgent: true, query: true },
|
|
250
|
+
level: "info",
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// Register before your routes
|
|
254
|
+
app.addHook("onRequest", cipher.fastify());
|
|
255
|
+
|
|
256
|
+
app.get("/", async () => ({ hello: "world" }));
|
|
257
|
+
|
|
258
|
+
app.listen({ port: 3000 });
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## NestJS
|
|
262
|
+
|
|
263
|
+
Use the Express-compatible middleware in Nest's runtime (works when Nest is using the Express platform):
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
import { NestFactory } from "@nestjs/core";
|
|
267
|
+
import { AppModule } from "./app.module";
|
|
268
|
+
import { createCipherLogger } from "cipher-logger";
|
|
269
|
+
|
|
270
|
+
async function bootstrap() {
|
|
271
|
+
const app = await NestFactory.create(AppModule);
|
|
272
|
+
|
|
273
|
+
const cipher = createCipherLogger({ fields: { ip: true, userAgent: true } });
|
|
274
|
+
|
|
275
|
+
// Mount as global middleware
|
|
276
|
+
app.use(cipher.nest());
|
|
277
|
+
|
|
278
|
+
await app.listen(3000);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
bootstrap();
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Hono
|
|
285
|
+
|
|
286
|
+
Mount the Hono middleware using `app.use` (works on edge and Node runtimes):
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
import { Hono } from "hono";
|
|
290
|
+
import { createCipherLogger } from "cipher-logger";
|
|
291
|
+
|
|
292
|
+
const app = new Hono();
|
|
293
|
+
|
|
294
|
+
const cipher = createCipherLogger({ fields: { ip: true, userAgent: true } });
|
|
295
|
+
|
|
296
|
+
// Mount for all routes
|
|
297
|
+
app.use("*", cipher.hono());
|
|
298
|
+
|
|
299
|
+
app.get("/", (c) => c.text("ok"));
|
|
300
|
+
|
|
301
|
+
app.listen({ port: 3000 });
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
|
|
225
305
|
## Log Schema
|
|
226
306
|
|
|
227
307
|
### Required Fields
|
|
@@ -301,6 +381,9 @@ import type {
|
|
|
301
381
|
LoggerOptions,
|
|
302
382
|
ExpressMiddleware,
|
|
303
383
|
NextMiddleware,
|
|
384
|
+
FastifyMiddleware,
|
|
385
|
+
NestMiddleware,
|
|
386
|
+
HonoMiddleware,
|
|
304
387
|
} from "cipher-logger";
|
|
305
388
|
```
|
|
306
389
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { Request, Response, NextFunction } from 'express';
|
|
1
|
+
import { Request, Response as Response$1, NextFunction } from 'express';
|
|
2
2
|
import { NextRequest, NextResponse } from 'next/server';
|
|
3
|
+
import { FastifyRequest, FastifyReply } from 'fastify';
|
|
4
|
+
import { Context } from 'hono';
|
|
3
5
|
|
|
4
6
|
type LogLevel = "info" | "warn" | "error" | "debug";
|
|
5
7
|
type LogMeta = Record<string, unknown>;
|
|
@@ -59,19 +61,31 @@ type CipherLoggerConfig = {
|
|
|
59
61
|
prefix?: string;
|
|
60
62
|
};
|
|
61
63
|
|
|
62
|
-
type ExpressMiddleware = (req: Request, res: Response, next: NextFunction) => void;
|
|
64
|
+
type ExpressMiddleware = (req: Request, res: Response$1, next: NextFunction) => void;
|
|
63
65
|
declare function createExpressMiddleware(cipher: CipherLogger): ExpressMiddleware;
|
|
64
66
|
|
|
65
67
|
type NextMiddleware = (request: NextRequest) => NextResponse | Promise<NextResponse>;
|
|
66
68
|
declare function createNextMiddleware(cipher: CipherLogger): NextMiddleware;
|
|
67
69
|
|
|
70
|
+
type FastifyMiddleware = (request: FastifyRequest, reply: FastifyReply) => void;
|
|
71
|
+
declare function createFastifyMiddleware(cipher: CipherLogger): FastifyMiddleware;
|
|
72
|
+
|
|
73
|
+
type NestMiddleware = (req: Request, res: Response$1, next: NextFunction) => void;
|
|
74
|
+
declare function createNestMiddleware(cipher: CipherLogger): NestMiddleware;
|
|
75
|
+
|
|
76
|
+
type HonoMiddleware = (c: Context, next: () => Promise<void>) => Response | Promise<Response>;
|
|
77
|
+
declare function createHonoMiddleware(cipher: CipherLogger): HonoMiddleware;
|
|
78
|
+
|
|
68
79
|
interface CipherLogger {
|
|
69
80
|
logRequest(input: RequestLogInput): RequestLog;
|
|
70
81
|
express(): ExpressMiddleware;
|
|
71
82
|
next(): NextMiddleware;
|
|
83
|
+
fastify(): FastifyMiddleware;
|
|
84
|
+
nest(): NestMiddleware;
|
|
85
|
+
hono(): HonoMiddleware;
|
|
72
86
|
}
|
|
73
87
|
declare function createCipherLogger(config?: CipherLoggerConfig): CipherLogger;
|
|
74
88
|
|
|
75
89
|
declare const logger: Logger;
|
|
76
90
|
|
|
77
|
-
export { type CipherLogger, type CipherLoggerConfig, type ExpressMiddleware, type LogLevel, type LogMeta, Logger, type LoggerOptions, type NextMiddleware, type OptionalRequestField, type RequestLog, type RequestLogInput, createCipherLogger, createExpressMiddleware, createNextMiddleware, logger, type RequestLog as request };
|
|
91
|
+
export { type CipherLogger, type CipherLoggerConfig, type ExpressMiddleware, type FastifyMiddleware, type HonoMiddleware, type LogLevel, type LogMeta, Logger, type LoggerOptions, type NestMiddleware, type NextMiddleware, type OptionalRequestField, type RequestLog, type RequestLogInput, createCipherLogger, createExpressMiddleware, createFastifyMiddleware, createHonoMiddleware, createNestMiddleware, createNextMiddleware, logger, type RequestLog as request };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { Request, Response, NextFunction } from 'express';
|
|
1
|
+
import { Request, Response as Response$1, NextFunction } from 'express';
|
|
2
2
|
import { NextRequest, NextResponse } from 'next/server';
|
|
3
|
+
import { FastifyRequest, FastifyReply } from 'fastify';
|
|
4
|
+
import { Context } from 'hono';
|
|
3
5
|
|
|
4
6
|
type LogLevel = "info" | "warn" | "error" | "debug";
|
|
5
7
|
type LogMeta = Record<string, unknown>;
|
|
@@ -59,19 +61,31 @@ type CipherLoggerConfig = {
|
|
|
59
61
|
prefix?: string;
|
|
60
62
|
};
|
|
61
63
|
|
|
62
|
-
type ExpressMiddleware = (req: Request, res: Response, next: NextFunction) => void;
|
|
64
|
+
type ExpressMiddleware = (req: Request, res: Response$1, next: NextFunction) => void;
|
|
63
65
|
declare function createExpressMiddleware(cipher: CipherLogger): ExpressMiddleware;
|
|
64
66
|
|
|
65
67
|
type NextMiddleware = (request: NextRequest) => NextResponse | Promise<NextResponse>;
|
|
66
68
|
declare function createNextMiddleware(cipher: CipherLogger): NextMiddleware;
|
|
67
69
|
|
|
70
|
+
type FastifyMiddleware = (request: FastifyRequest, reply: FastifyReply) => void;
|
|
71
|
+
declare function createFastifyMiddleware(cipher: CipherLogger): FastifyMiddleware;
|
|
72
|
+
|
|
73
|
+
type NestMiddleware = (req: Request, res: Response$1, next: NextFunction) => void;
|
|
74
|
+
declare function createNestMiddleware(cipher: CipherLogger): NestMiddleware;
|
|
75
|
+
|
|
76
|
+
type HonoMiddleware = (c: Context, next: () => Promise<void>) => Response | Promise<Response>;
|
|
77
|
+
declare function createHonoMiddleware(cipher: CipherLogger): HonoMiddleware;
|
|
78
|
+
|
|
68
79
|
interface CipherLogger {
|
|
69
80
|
logRequest(input: RequestLogInput): RequestLog;
|
|
70
81
|
express(): ExpressMiddleware;
|
|
71
82
|
next(): NextMiddleware;
|
|
83
|
+
fastify(): FastifyMiddleware;
|
|
84
|
+
nest(): NestMiddleware;
|
|
85
|
+
hono(): HonoMiddleware;
|
|
72
86
|
}
|
|
73
87
|
declare function createCipherLogger(config?: CipherLoggerConfig): CipherLogger;
|
|
74
88
|
|
|
75
89
|
declare const logger: Logger;
|
|
76
90
|
|
|
77
|
-
export { type CipherLogger, type CipherLoggerConfig, type ExpressMiddleware, type LogLevel, type LogMeta, Logger, type LoggerOptions, type NextMiddleware, type OptionalRequestField, type RequestLog, type RequestLogInput, createCipherLogger, createExpressMiddleware, createNextMiddleware, logger, type RequestLog as request };
|
|
91
|
+
export { type CipherLogger, type CipherLoggerConfig, type ExpressMiddleware, type FastifyMiddleware, type HonoMiddleware, type LogLevel, type LogMeta, Logger, type LoggerOptions, type NestMiddleware, type NextMiddleware, type OptionalRequestField, type RequestLog, type RequestLogInput, createCipherLogger, createExpressMiddleware, createFastifyMiddleware, createHonoMiddleware, createNestMiddleware, createNextMiddleware, logger, type RequestLog as request };
|
package/dist/index.js
CHANGED
|
@@ -23,6 +23,9 @@ __export(src_exports, {
|
|
|
23
23
|
Logger: () => Logger,
|
|
24
24
|
createCipherLogger: () => createCipherLogger,
|
|
25
25
|
createExpressMiddleware: () => createExpressMiddleware,
|
|
26
|
+
createFastifyMiddleware: () => createFastifyMiddleware,
|
|
27
|
+
createHonoMiddleware: () => createHonoMiddleware,
|
|
28
|
+
createNestMiddleware: () => createNestMiddleware,
|
|
26
29
|
createNextMiddleware: () => createNextMiddleware,
|
|
27
30
|
logger: () => logger
|
|
28
31
|
});
|
|
@@ -224,6 +227,145 @@ function createNextMiddleware(cipher) {
|
|
|
224
227
|
};
|
|
225
228
|
}
|
|
226
229
|
|
|
230
|
+
// src/adapters/fastify/middleware.ts
|
|
231
|
+
function getHeader3(req, name) {
|
|
232
|
+
const value = req.headers[name];
|
|
233
|
+
if (value === void 0) {
|
|
234
|
+
return void 0;
|
|
235
|
+
}
|
|
236
|
+
return Array.isArray(value) ? String(value[0]) : String(value);
|
|
237
|
+
}
|
|
238
|
+
function parseQuery3(req) {
|
|
239
|
+
try {
|
|
240
|
+
const raw = req.raw.url ?? req.url ?? "";
|
|
241
|
+
const url = new URL(raw, "http://localhost");
|
|
242
|
+
const result = {};
|
|
243
|
+
for (const [key, value] of url.searchParams.entries()) {
|
|
244
|
+
result[key] = value;
|
|
245
|
+
}
|
|
246
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
247
|
+
} catch {
|
|
248
|
+
return void 0;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function createFastifyMiddleware(cipher) {
|
|
252
|
+
return (request, reply) => {
|
|
253
|
+
const start = Date.now();
|
|
254
|
+
reply.raw.once("finish", () => {
|
|
255
|
+
const protocol = request.headers["x-forwarded-proto"] || (request.raw.socket && request.raw.socket.encrypted ? "https" : "http");
|
|
256
|
+
cipher.logRequest({
|
|
257
|
+
method: request.method,
|
|
258
|
+
path: request.raw.url ?? request.url,
|
|
259
|
+
status: reply.statusCode,
|
|
260
|
+
duration: Date.now() - start,
|
|
261
|
+
ip: request.headers["x-forwarded-for"] ? request.headers["x-forwarded-for"].split(",")[0].trim() : request.ip || request.socket?.remoteAddress || request.raw.socket?.remoteAddress,
|
|
262
|
+
userAgent: getHeader3(request, "user-agent"),
|
|
263
|
+
referer: getHeader3(request, "referer"),
|
|
264
|
+
protocol,
|
|
265
|
+
host: getHeader3(request, "host"),
|
|
266
|
+
query: parseQuery3(request),
|
|
267
|
+
requestId: getHeader3(request, "x-request-id")
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// src/adapters/nest/middleware.ts
|
|
274
|
+
function parseQuery4(query) {
|
|
275
|
+
const result = {};
|
|
276
|
+
for (const [key, value] of Object.entries(query)) {
|
|
277
|
+
if (value === void 0) {
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
result[key] = typeof value === "string" ? value : Array.isArray(value) ? String(value[0] ?? "") : String(value);
|
|
281
|
+
}
|
|
282
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
283
|
+
}
|
|
284
|
+
function getHeader4(req, name) {
|
|
285
|
+
const value = req.headers[name];
|
|
286
|
+
if (value === void 0) {
|
|
287
|
+
return void 0;
|
|
288
|
+
}
|
|
289
|
+
return Array.isArray(value) ? value[0] : value;
|
|
290
|
+
}
|
|
291
|
+
function createNestMiddleware(cipher) {
|
|
292
|
+
return (req, res, next) => {
|
|
293
|
+
const start = Date.now();
|
|
294
|
+
res.on("finish", () => {
|
|
295
|
+
cipher.logRequest({
|
|
296
|
+
method: req.method,
|
|
297
|
+
path: req.originalUrl || req.url,
|
|
298
|
+
status: res.statusCode,
|
|
299
|
+
duration: Date.now() - start,
|
|
300
|
+
ip: req.headers["x-forwarded-for"]?.split(",")[0]?.trim() || req.ip || req.socket.remoteAddress,
|
|
301
|
+
userAgent: getHeader4(req, "user-agent"),
|
|
302
|
+
referer: getHeader4(req, "referer"),
|
|
303
|
+
protocol: req.protocol,
|
|
304
|
+
host: getHeader4(req, "host"),
|
|
305
|
+
query: parseQuery4(req.query),
|
|
306
|
+
requestId: getHeader4(req, "x-request-id")
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
next();
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// src/adapters/hono/middleware.ts
|
|
314
|
+
function getHeader5(request, name) {
|
|
315
|
+
if (!request) return void 0;
|
|
316
|
+
if (typeof request.header === "function") {
|
|
317
|
+
return request.header(name) ?? void 0;
|
|
318
|
+
}
|
|
319
|
+
if (request.headers && typeof request.headers.get === "function") {
|
|
320
|
+
return request.headers.get(name) ?? void 0;
|
|
321
|
+
}
|
|
322
|
+
return void 0;
|
|
323
|
+
}
|
|
324
|
+
function parseQuery5(urlString) {
|
|
325
|
+
try {
|
|
326
|
+
const url = new URL(urlString);
|
|
327
|
+
const result = {};
|
|
328
|
+
for (const [key, value] of url.searchParams.entries()) {
|
|
329
|
+
result[key] = value;
|
|
330
|
+
}
|
|
331
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
332
|
+
} catch {
|
|
333
|
+
return void 0;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
function createHonoMiddleware(cipher) {
|
|
337
|
+
return async (c, next) => {
|
|
338
|
+
const start = Date.now();
|
|
339
|
+
await next();
|
|
340
|
+
const req = c.req ?? c.request;
|
|
341
|
+
const url = typeof req?.url === "string" ? req.url : String(req?.url ?? "");
|
|
342
|
+
const parsed = new URL(url, "http://localhost");
|
|
343
|
+
let status = 200;
|
|
344
|
+
const cres = c.res ?? c.response ?? void 0;
|
|
345
|
+
if (cres && typeof cres.status === "number") {
|
|
346
|
+
status = cres.status;
|
|
347
|
+
} else if (cres && typeof cres.statusCode === "number") {
|
|
348
|
+
status = cres.statusCode;
|
|
349
|
+
}
|
|
350
|
+
const xfwd = getHeader5(req, "x-forwarded-for");
|
|
351
|
+
const ip = xfwd ? String(xfwd).split(",")[0].trim() : getHeader5(req, "x-real-ip") ?? void 0;
|
|
352
|
+
cipher.logRequest({
|
|
353
|
+
method: req?.method,
|
|
354
|
+
path: parsed.pathname + parsed.search,
|
|
355
|
+
status,
|
|
356
|
+
duration: Date.now() - start,
|
|
357
|
+
ip,
|
|
358
|
+
userAgent: getHeader5(req, "user-agent"),
|
|
359
|
+
referer: getHeader5(req, "referer"),
|
|
360
|
+
protocol: parsed.protocol.replace(":", ""),
|
|
361
|
+
host: getHeader5(req, "host"),
|
|
362
|
+
query: parseQuery5(url),
|
|
363
|
+
requestId: getHeader5(req, "x-request-id")
|
|
364
|
+
});
|
|
365
|
+
return cres ?? new Response(null, { status });
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
|
|
227
369
|
// src/core/create-cipher-logger.ts
|
|
228
370
|
function createCipherLogger(config = {}) {
|
|
229
371
|
const fields = resolveFieldConfig(config.fields);
|
|
@@ -242,6 +384,15 @@ function createCipherLogger(config = {}) {
|
|
|
242
384
|
},
|
|
243
385
|
next() {
|
|
244
386
|
return createNextMiddleware(cipherLogger);
|
|
387
|
+
},
|
|
388
|
+
fastify() {
|
|
389
|
+
return createFastifyMiddleware(cipherLogger);
|
|
390
|
+
},
|
|
391
|
+
nest() {
|
|
392
|
+
return createNestMiddleware(cipherLogger);
|
|
393
|
+
},
|
|
394
|
+
hono() {
|
|
395
|
+
return createHonoMiddleware(cipherLogger);
|
|
245
396
|
}
|
|
246
397
|
};
|
|
247
398
|
return cipherLogger;
|
|
@@ -254,6 +405,9 @@ var logger = new Logger();
|
|
|
254
405
|
Logger,
|
|
255
406
|
createCipherLogger,
|
|
256
407
|
createExpressMiddleware,
|
|
408
|
+
createFastifyMiddleware,
|
|
409
|
+
createHonoMiddleware,
|
|
410
|
+
createNestMiddleware,
|
|
257
411
|
createNextMiddleware,
|
|
258
412
|
logger
|
|
259
413
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -194,6 +194,145 @@ function createNextMiddleware(cipher) {
|
|
|
194
194
|
};
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
// src/adapters/fastify/middleware.ts
|
|
198
|
+
function getHeader3(req, name) {
|
|
199
|
+
const value = req.headers[name];
|
|
200
|
+
if (value === void 0) {
|
|
201
|
+
return void 0;
|
|
202
|
+
}
|
|
203
|
+
return Array.isArray(value) ? String(value[0]) : String(value);
|
|
204
|
+
}
|
|
205
|
+
function parseQuery3(req) {
|
|
206
|
+
try {
|
|
207
|
+
const raw = req.raw.url ?? req.url ?? "";
|
|
208
|
+
const url = new URL(raw, "http://localhost");
|
|
209
|
+
const result = {};
|
|
210
|
+
for (const [key, value] of url.searchParams.entries()) {
|
|
211
|
+
result[key] = value;
|
|
212
|
+
}
|
|
213
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
214
|
+
} catch {
|
|
215
|
+
return void 0;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
function createFastifyMiddleware(cipher) {
|
|
219
|
+
return (request, reply) => {
|
|
220
|
+
const start = Date.now();
|
|
221
|
+
reply.raw.once("finish", () => {
|
|
222
|
+
const protocol = request.headers["x-forwarded-proto"] || (request.raw.socket && request.raw.socket.encrypted ? "https" : "http");
|
|
223
|
+
cipher.logRequest({
|
|
224
|
+
method: request.method,
|
|
225
|
+
path: request.raw.url ?? request.url,
|
|
226
|
+
status: reply.statusCode,
|
|
227
|
+
duration: Date.now() - start,
|
|
228
|
+
ip: request.headers["x-forwarded-for"] ? request.headers["x-forwarded-for"].split(",")[0].trim() : request.ip || request.socket?.remoteAddress || request.raw.socket?.remoteAddress,
|
|
229
|
+
userAgent: getHeader3(request, "user-agent"),
|
|
230
|
+
referer: getHeader3(request, "referer"),
|
|
231
|
+
protocol,
|
|
232
|
+
host: getHeader3(request, "host"),
|
|
233
|
+
query: parseQuery3(request),
|
|
234
|
+
requestId: getHeader3(request, "x-request-id")
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// src/adapters/nest/middleware.ts
|
|
241
|
+
function parseQuery4(query) {
|
|
242
|
+
const result = {};
|
|
243
|
+
for (const [key, value] of Object.entries(query)) {
|
|
244
|
+
if (value === void 0) {
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
result[key] = typeof value === "string" ? value : Array.isArray(value) ? String(value[0] ?? "") : String(value);
|
|
248
|
+
}
|
|
249
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
250
|
+
}
|
|
251
|
+
function getHeader4(req, name) {
|
|
252
|
+
const value = req.headers[name];
|
|
253
|
+
if (value === void 0) {
|
|
254
|
+
return void 0;
|
|
255
|
+
}
|
|
256
|
+
return Array.isArray(value) ? value[0] : value;
|
|
257
|
+
}
|
|
258
|
+
function createNestMiddleware(cipher) {
|
|
259
|
+
return (req, res, next) => {
|
|
260
|
+
const start = Date.now();
|
|
261
|
+
res.on("finish", () => {
|
|
262
|
+
cipher.logRequest({
|
|
263
|
+
method: req.method,
|
|
264
|
+
path: req.originalUrl || req.url,
|
|
265
|
+
status: res.statusCode,
|
|
266
|
+
duration: Date.now() - start,
|
|
267
|
+
ip: req.headers["x-forwarded-for"]?.split(",")[0]?.trim() || req.ip || req.socket.remoteAddress,
|
|
268
|
+
userAgent: getHeader4(req, "user-agent"),
|
|
269
|
+
referer: getHeader4(req, "referer"),
|
|
270
|
+
protocol: req.protocol,
|
|
271
|
+
host: getHeader4(req, "host"),
|
|
272
|
+
query: parseQuery4(req.query),
|
|
273
|
+
requestId: getHeader4(req, "x-request-id")
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
next();
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// src/adapters/hono/middleware.ts
|
|
281
|
+
function getHeader5(request, name) {
|
|
282
|
+
if (!request) return void 0;
|
|
283
|
+
if (typeof request.header === "function") {
|
|
284
|
+
return request.header(name) ?? void 0;
|
|
285
|
+
}
|
|
286
|
+
if (request.headers && typeof request.headers.get === "function") {
|
|
287
|
+
return request.headers.get(name) ?? void 0;
|
|
288
|
+
}
|
|
289
|
+
return void 0;
|
|
290
|
+
}
|
|
291
|
+
function parseQuery5(urlString) {
|
|
292
|
+
try {
|
|
293
|
+
const url = new URL(urlString);
|
|
294
|
+
const result = {};
|
|
295
|
+
for (const [key, value] of url.searchParams.entries()) {
|
|
296
|
+
result[key] = value;
|
|
297
|
+
}
|
|
298
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
299
|
+
} catch {
|
|
300
|
+
return void 0;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function createHonoMiddleware(cipher) {
|
|
304
|
+
return async (c, next) => {
|
|
305
|
+
const start = Date.now();
|
|
306
|
+
await next();
|
|
307
|
+
const req = c.req ?? c.request;
|
|
308
|
+
const url = typeof req?.url === "string" ? req.url : String(req?.url ?? "");
|
|
309
|
+
const parsed = new URL(url, "http://localhost");
|
|
310
|
+
let status = 200;
|
|
311
|
+
const cres = c.res ?? c.response ?? void 0;
|
|
312
|
+
if (cres && typeof cres.status === "number") {
|
|
313
|
+
status = cres.status;
|
|
314
|
+
} else if (cres && typeof cres.statusCode === "number") {
|
|
315
|
+
status = cres.statusCode;
|
|
316
|
+
}
|
|
317
|
+
const xfwd = getHeader5(req, "x-forwarded-for");
|
|
318
|
+
const ip = xfwd ? String(xfwd).split(",")[0].trim() : getHeader5(req, "x-real-ip") ?? void 0;
|
|
319
|
+
cipher.logRequest({
|
|
320
|
+
method: req?.method,
|
|
321
|
+
path: parsed.pathname + parsed.search,
|
|
322
|
+
status,
|
|
323
|
+
duration: Date.now() - start,
|
|
324
|
+
ip,
|
|
325
|
+
userAgent: getHeader5(req, "user-agent"),
|
|
326
|
+
referer: getHeader5(req, "referer"),
|
|
327
|
+
protocol: parsed.protocol.replace(":", ""),
|
|
328
|
+
host: getHeader5(req, "host"),
|
|
329
|
+
query: parseQuery5(url),
|
|
330
|
+
requestId: getHeader5(req, "x-request-id")
|
|
331
|
+
});
|
|
332
|
+
return cres ?? new Response(null, { status });
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
197
336
|
// src/core/create-cipher-logger.ts
|
|
198
337
|
function createCipherLogger(config = {}) {
|
|
199
338
|
const fields = resolveFieldConfig(config.fields);
|
|
@@ -212,6 +351,15 @@ function createCipherLogger(config = {}) {
|
|
|
212
351
|
},
|
|
213
352
|
next() {
|
|
214
353
|
return createNextMiddleware(cipherLogger);
|
|
354
|
+
},
|
|
355
|
+
fastify() {
|
|
356
|
+
return createFastifyMiddleware(cipherLogger);
|
|
357
|
+
},
|
|
358
|
+
nest() {
|
|
359
|
+
return createNestMiddleware(cipherLogger);
|
|
360
|
+
},
|
|
361
|
+
hono() {
|
|
362
|
+
return createHonoMiddleware(cipherLogger);
|
|
215
363
|
}
|
|
216
364
|
};
|
|
217
365
|
return cipherLogger;
|
|
@@ -223,6 +371,9 @@ export {
|
|
|
223
371
|
Logger,
|
|
224
372
|
createCipherLogger,
|
|
225
373
|
createExpressMiddleware,
|
|
374
|
+
createFastifyMiddleware,
|
|
375
|
+
createHonoMiddleware,
|
|
376
|
+
createNestMiddleware,
|
|
226
377
|
createNextMiddleware,
|
|
227
378
|
logger
|
|
228
379
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cipher-logger",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "See every request. Capture every error. Understand your application.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -43,6 +43,13 @@
|
|
|
43
43
|
"nextjs-middleware",
|
|
44
44
|
"express",
|
|
45
45
|
"express-logger",
|
|
46
|
+
"fastify",
|
|
47
|
+
"fastify-logger",
|
|
48
|
+
"nest",
|
|
49
|
+
"nestjs",
|
|
50
|
+
"nestjs-logger",
|
|
51
|
+
"hono",
|
|
52
|
+
"hono-logger",
|
|
46
53
|
"cli",
|
|
47
54
|
"dashboard",
|
|
48
55
|
"cipherlogger",
|
|
@@ -54,7 +61,11 @@
|
|
|
54
61
|
"type": "commonjs",
|
|
55
62
|
"peerDependencies": {
|
|
56
63
|
"express": ">=4",
|
|
57
|
-
"next": ">=13"
|
|
64
|
+
"next": ">=13",
|
|
65
|
+
"fastify": ">=4",
|
|
66
|
+
"hono": ">=1",
|
|
67
|
+
"@nestjs/common": ">=10",
|
|
68
|
+
"@nestjs/core": ">=10"
|
|
58
69
|
},
|
|
59
70
|
"peerDependenciesMeta": {
|
|
60
71
|
"express": {
|
|
@@ -63,6 +74,19 @@
|
|
|
63
74
|
"next": {
|
|
64
75
|
"optional": true
|
|
65
76
|
}
|
|
77
|
+
,
|
|
78
|
+
"fastify": {
|
|
79
|
+
"optional": true
|
|
80
|
+
},
|
|
81
|
+
"hono": {
|
|
82
|
+
"optional": true
|
|
83
|
+
},
|
|
84
|
+
"@nestjs/common": {
|
|
85
|
+
"optional": true
|
|
86
|
+
},
|
|
87
|
+
"@nestjs/core": {
|
|
88
|
+
"optional": true
|
|
89
|
+
}
|
|
66
90
|
},
|
|
67
91
|
"devDependencies": {
|
|
68
92
|
"@types/express": "^5.0.3",
|