cipher-logger 1.1.0 → 1.3.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/.editorconfig ADDED
@@ -0,0 +1,19 @@
1
+ # http://editorconfig.org
2
+ root = true
3
+
4
+ [*]
5
+ charset = utf-8
6
+ end_of_line = lf
7
+ insert_final_newline = true
8
+ indent_style = space
9
+ indent_size = 2
10
+ trim_trailing_whitespace = true
11
+
12
+ [*.md]
13
+ trim_trailing_whitespace = false
14
+
15
+ [Makefile]
16
+ indent_style = tab
17
+
18
+ [*.{yml,yaml}]
19
+ indent_size = 2
package/.gitattributes ADDED
File without changes
@@ -0,0 +1,36 @@
1
+ name: Pre-publish validation
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ validate:
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - name: Checkout
16
+ uses: actions/checkout@v4
17
+
18
+ - name: Setup pnpm
19
+ uses: pnpm/action-setup@v4
20
+ with:
21
+ version: 10
22
+
23
+ - name: Setup Node.js
24
+ uses: actions/setup-node@v4
25
+ with:
26
+ node-version: 24
27
+ cache: pnpm
28
+
29
+ - name: Install dependencies
30
+ run: pnpm install --frozen-lockfile
31
+
32
+ - name: Run validation suite
33
+ run: pnpm run test
34
+
35
+ - name: Dry run package publish
36
+ run: npm pack --dry-run
@@ -1,9 +1,9 @@
1
1
  name: Publish to npm
2
2
 
3
3
  on:
4
- push:
5
- branches:
6
- - main
4
+ workflow_run:
5
+ workflows: ["Pre-publish validation"]
6
+ types: [completed]
7
7
 
8
8
  permissions:
9
9
  contents: read
@@ -11,11 +11,14 @@ permissions:
11
11
 
12
12
  jobs:
13
13
  publish:
14
+ if: ${{ github.event.workflow_run.conclusion == 'success' }}
14
15
  runs-on: ubuntu-latest
15
16
 
16
17
  steps:
17
18
  - name: Checkout
18
19
  uses: actions/checkout@v4
20
+ with:
21
+ ref: ${{ github.event.workflow_run.head_sha }}
19
22
 
20
23
  - name: Setup pnpm
21
24
  uses: pnpm/action-setup@v4
@@ -41,9 +44,6 @@ jobs:
41
44
  - name: Install dependencies
42
45
  run: pnpm install --frozen-lockfile
43
46
 
44
- - name: Build
45
- run: pnpm run build
46
-
47
47
  - name: Publish
48
48
  run: |
49
49
  NAME=$(node -p "require('./package.json').name")
@@ -0,0 +1 @@
1
+ pnpm exec commitlint --edit "$1"
@@ -0,0 +1,4 @@
1
+ # #!/usr/bin/env sh
2
+ # . "$(dirname -- "$0")/_/husky.sh"
3
+
4
+ pnpm build
@@ -0,0 +1,11 @@
1
+ node_modules
2
+ .next
3
+ .turbo
4
+ dist
5
+ build
6
+ examples
7
+ pnpm-lock.yaml
8
+ package-lock.json
9
+ yarn.lock
10
+ *.log
11
+ .agents
package/README.md CHANGED
@@ -23,7 +23,7 @@
23
23
 
24
24
  ---
25
25
 
26
- **Cipher Logger** is a lightweight, production-ready HTTP logging library for Node.js. It captures every request in **Express** and **Next.js** applications. You decide exactly which fields appear in each log — required fields are always recorded, optional fields are opt-in.
26
+ **Cipher Logger** is a lightweight, production-ready HTTP logging library for Node.js. It captures every request in **Express**, **Next.js**, **React**, **Vue**, and **Nuxt** applications. You decide exactly which fields appear in each log — required fields are always recorded, optional fields are opt-in.
27
27
 
28
28
  ## Table of Contents
29
29
 
@@ -48,11 +48,11 @@
48
48
  - **Configurable fields** — fine-grained control over optional log fields
49
49
  - **Express middleware** — records real `status` and `duration` after the response finishes
50
50
  - **Next.js middleware** — drop-in support for `middleware.ts`
51
- - **Zero heavy dependencies** — only `express` or `next` as optional peer dependencies
52
- - **Fastify middleware** — lightweight hook-compatible middleware for Fastify
53
- - **NestJS middleware** — Express-compatible middleware for Nest apps
54
- - **Hono middleware** — edge-friendly middleware for Hono apps
55
- - **Zero heavy dependencies** — only framework peers are optional
51
+ - **React**, **Vue**, and **Nuxt** support modern app stacks alongside the server frameworks
52
+ - **Zero heavy dependencies** — only framework peers are optional
53
+ - **Fastify middleware** — lightweight hook-compatible middleware for Fastify
54
+ - **NestJS middleware** — Express-compatible middleware for Nest apps
55
+ - **Hono middleware** — edge-friendly middleware for Hono apps
56
56
  - **Node.js 18+** compatible
57
57
 
58
58
  ---
@@ -78,6 +78,15 @@ npm install express
78
78
  # Next.js
79
79
  npm install next
80
80
 
81
+ # React
82
+ npm install react
83
+
84
+ # Vue
85
+ npm install vue
86
+
87
+ # Nuxt
88
+ npm install nuxt
89
+
81
90
  # Fastify
82
91
  npm install fastify
83
92
 
@@ -0,0 +1,26 @@
1
+ /** @type {import('@commitlint/types').UserConfig} */
2
+ export default {
3
+ extends: ['@commitlint/config-conventional'],
4
+ rules: {
5
+ 'type-enum': [
6
+ 2,
7
+ 'always',
8
+ [
9
+ 'feat',
10
+ 'fix',
11
+ 'docs',
12
+ 'i18n',
13
+ 'style',
14
+ 'refactor',
15
+ 'perf',
16
+ 'test',
17
+ 'build',
18
+ 'ci',
19
+ 'chore',
20
+ 'revert',
21
+ ],
22
+ ],
23
+ 'subject-case': [2, 'never', ['start-case', 'pascal-case', 'upper-case']],
24
+ 'header-max-length': [2, 'always', 100],
25
+ },
26
+ };
package/dist/index.d.mts CHANGED
@@ -76,10 +76,49 @@ declare function createNestMiddleware(cipher: CipherLogger): NestMiddleware;
76
76
  type HonoMiddleware = (c: Context, next: () => Promise<void>) => Response | Promise<Response>;
77
77
  declare function createHonoMiddleware(cipher: CipherLogger): HonoMiddleware;
78
78
 
79
+ type ReactRequest = {
80
+ method: string;
81
+ url: string;
82
+ headers: Headers | Record<string, string | string[] | undefined>;
83
+ };
84
+ type ReactResponse = {
85
+ status?: number;
86
+ end: (...args: unknown[]) => unknown;
87
+ };
88
+ type ReactMiddleware = (req: ReactRequest, res: ReactResponse) => void;
89
+ declare function createReactMiddleware(cipher: CipherLogger): ReactMiddleware;
90
+
91
+ type VueRequest = {
92
+ method: string;
93
+ url: string;
94
+ headers: Headers | Record<string, string | string[] | undefined>;
95
+ };
96
+ type VueResponse = {
97
+ status?: number;
98
+ end: (...args: unknown[]) => unknown;
99
+ };
100
+ type VueMiddleware = (req: VueRequest, res: VueResponse) => void;
101
+ declare function createVueMiddleware(cipher: CipherLogger): VueMiddleware;
102
+
103
+ type NuxtRequest = {
104
+ method: string;
105
+ url: string;
106
+ headers: Headers | Record<string, string | string[] | undefined>;
107
+ };
108
+ type NuxtResponse = {
109
+ status?: number;
110
+ end: (...args: unknown[]) => unknown;
111
+ };
112
+ type NuxtMiddleware = (req: NuxtRequest, res: NuxtResponse) => void;
113
+ declare function createNuxtMiddleware(cipher: CipherLogger): NuxtMiddleware;
114
+
79
115
  interface CipherLogger {
80
116
  logRequest(input: RequestLogInput): RequestLog;
81
117
  express(): ExpressMiddleware;
82
118
  next(): NextMiddleware;
119
+ react(): ReactMiddleware;
120
+ vue(): VueMiddleware;
121
+ nuxt(): NuxtMiddleware;
83
122
  fastify(): FastifyMiddleware;
84
123
  nest(): NestMiddleware;
85
124
  hono(): HonoMiddleware;
@@ -88,4 +127,4 @@ declare function createCipherLogger(config?: CipherLoggerConfig): CipherLogger;
88
127
 
89
128
  declare const logger: Logger;
90
129
 
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 };
130
+ export { type CipherLogger, type CipherLoggerConfig, type ExpressMiddleware, type FastifyMiddleware, type HonoMiddleware, type LogLevel, type LogMeta, Logger, type LoggerOptions, type NestMiddleware, type NextMiddleware, type NuxtMiddleware, type OptionalRequestField, type ReactMiddleware, type RequestLog, type RequestLogInput, type VueMiddleware, createCipherLogger, createExpressMiddleware, createFastifyMiddleware, createHonoMiddleware, createNestMiddleware, createNextMiddleware, createNuxtMiddleware, createReactMiddleware, createVueMiddleware, logger, type RequestLog as request };
package/dist/index.d.ts CHANGED
@@ -76,10 +76,49 @@ declare function createNestMiddleware(cipher: CipherLogger): NestMiddleware;
76
76
  type HonoMiddleware = (c: Context, next: () => Promise<void>) => Response | Promise<Response>;
77
77
  declare function createHonoMiddleware(cipher: CipherLogger): HonoMiddleware;
78
78
 
79
+ type ReactRequest = {
80
+ method: string;
81
+ url: string;
82
+ headers: Headers | Record<string, string | string[] | undefined>;
83
+ };
84
+ type ReactResponse = {
85
+ status?: number;
86
+ end: (...args: unknown[]) => unknown;
87
+ };
88
+ type ReactMiddleware = (req: ReactRequest, res: ReactResponse) => void;
89
+ declare function createReactMiddleware(cipher: CipherLogger): ReactMiddleware;
90
+
91
+ type VueRequest = {
92
+ method: string;
93
+ url: string;
94
+ headers: Headers | Record<string, string | string[] | undefined>;
95
+ };
96
+ type VueResponse = {
97
+ status?: number;
98
+ end: (...args: unknown[]) => unknown;
99
+ };
100
+ type VueMiddleware = (req: VueRequest, res: VueResponse) => void;
101
+ declare function createVueMiddleware(cipher: CipherLogger): VueMiddleware;
102
+
103
+ type NuxtRequest = {
104
+ method: string;
105
+ url: string;
106
+ headers: Headers | Record<string, string | string[] | undefined>;
107
+ };
108
+ type NuxtResponse = {
109
+ status?: number;
110
+ end: (...args: unknown[]) => unknown;
111
+ };
112
+ type NuxtMiddleware = (req: NuxtRequest, res: NuxtResponse) => void;
113
+ declare function createNuxtMiddleware(cipher: CipherLogger): NuxtMiddleware;
114
+
79
115
  interface CipherLogger {
80
116
  logRequest(input: RequestLogInput): RequestLog;
81
117
  express(): ExpressMiddleware;
82
118
  next(): NextMiddleware;
119
+ react(): ReactMiddleware;
120
+ vue(): VueMiddleware;
121
+ nuxt(): NuxtMiddleware;
83
122
  fastify(): FastifyMiddleware;
84
123
  nest(): NestMiddleware;
85
124
  hono(): HonoMiddleware;
@@ -88,4 +127,4 @@ declare function createCipherLogger(config?: CipherLoggerConfig): CipherLogger;
88
127
 
89
128
  declare const logger: Logger;
90
129
 
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 };
130
+ export { type CipherLogger, type CipherLoggerConfig, type ExpressMiddleware, type FastifyMiddleware, type HonoMiddleware, type LogLevel, type LogMeta, Logger, type LoggerOptions, type NestMiddleware, type NextMiddleware, type NuxtMiddleware, type OptionalRequestField, type ReactMiddleware, type RequestLog, type RequestLogInput, type VueMiddleware, createCipherLogger, createExpressMiddleware, createFastifyMiddleware, createHonoMiddleware, createNestMiddleware, createNextMiddleware, createNuxtMiddleware, createReactMiddleware, createVueMiddleware, logger, type RequestLog as request };
package/dist/index.js CHANGED
@@ -27,6 +27,9 @@ __export(src_exports, {
27
27
  createHonoMiddleware: () => createHonoMiddleware,
28
28
  createNestMiddleware: () => createNestMiddleware,
29
29
  createNextMiddleware: () => createNextMiddleware,
30
+ createNuxtMiddleware: () => createNuxtMiddleware,
31
+ createReactMiddleware: () => createReactMiddleware,
32
+ createVueMiddleware: () => createVueMiddleware,
30
33
  logger: () => logger
31
34
  });
32
35
  module.exports = __toCommonJS(src_exports);
@@ -312,7 +315,9 @@ function createNestMiddleware(cipher) {
312
315
 
313
316
  // src/adapters/hono/middleware.ts
314
317
  function getHeader5(request, name) {
315
- if (!request) return void 0;
318
+ if (!request) {
319
+ return void 0;
320
+ }
316
321
  if (typeof request.header === "function") {
317
322
  return request.header(name) ?? void 0;
318
323
  }
@@ -321,6 +326,9 @@ function getHeader5(request, name) {
321
326
  }
322
327
  return void 0;
323
328
  }
329
+ function hasHeader(request, name) {
330
+ return Boolean(getHeader5(request, name));
331
+ }
324
332
  function parseQuery5(urlString) {
325
333
  try {
326
334
  const url = new URL(urlString);
@@ -348,7 +356,7 @@ function createHonoMiddleware(cipher) {
348
356
  status = cres.statusCode;
349
357
  }
350
358
  const xfwd = getHeader5(req, "x-forwarded-for");
351
- const ip = xfwd ? String(xfwd).split(",")[0].trim() : getHeader5(req, "x-real-ip") ?? void 0;
359
+ const ip = hasHeader(req, "x-forwarded-for") ? String(xfwd).split(",")[0].trim() : getHeader5(req, "x-real-ip") ?? void 0;
352
360
  cipher.logRequest({
353
361
  method: req?.method,
354
362
  path: parsed.pathname + parsed.search,
@@ -366,6 +374,132 @@ function createHonoMiddleware(cipher) {
366
374
  };
367
375
  }
368
376
 
377
+ // src/adapters/react/middleware.ts
378
+ function getHeader6(request, name) {
379
+ if (request.headers instanceof Headers) {
380
+ return request.headers.get(name) ?? void 0;
381
+ }
382
+ const value = request.headers[name.toLowerCase()];
383
+ if (Array.isArray(value)) {
384
+ return value[0];
385
+ }
386
+ return value ?? void 0;
387
+ }
388
+ function parseQuery6(url) {
389
+ const result = {};
390
+ for (const [key, value] of url.searchParams.entries()) {
391
+ result[key] = value;
392
+ }
393
+ return Object.keys(result).length > 0 ? result : void 0;
394
+ }
395
+ function createReactMiddleware(cipher) {
396
+ return (req, res) => {
397
+ const start = Date.now();
398
+ const originalEnd = res.end.bind(res);
399
+ res.end = ((...args) => {
400
+ const url = new URL(req.url, "http://localhost");
401
+ cipher.logRequest({
402
+ method: req.method,
403
+ path: url.pathname + url.search,
404
+ status: res.status ?? 200,
405
+ duration: Date.now() - start,
406
+ ip: getHeader6(req, "x-forwarded-for")?.split(",")[0]?.trim() ?? getHeader6(req, "x-real-ip"),
407
+ userAgent: getHeader6(req, "user-agent"),
408
+ referer: getHeader6(req, "referer"),
409
+ protocol: url.protocol.replace(":", ""),
410
+ host: getHeader6(req, "host"),
411
+ query: parseQuery6(url),
412
+ requestId: getHeader6(req, "x-request-id")
413
+ });
414
+ return originalEnd(...args);
415
+ });
416
+ };
417
+ }
418
+
419
+ // src/adapters/vue/middleware.ts
420
+ function getHeader7(request, name) {
421
+ if (request.headers instanceof Headers) {
422
+ return request.headers.get(name) ?? void 0;
423
+ }
424
+ const value = request.headers[name.toLowerCase()];
425
+ if (Array.isArray(value)) {
426
+ return value[0];
427
+ }
428
+ return value ?? void 0;
429
+ }
430
+ function parseQuery7(url) {
431
+ const result = {};
432
+ for (const [key, value] of url.searchParams.entries()) {
433
+ result[key] = value;
434
+ }
435
+ return Object.keys(result).length > 0 ? result : void 0;
436
+ }
437
+ function createVueMiddleware(cipher) {
438
+ return (req, res) => {
439
+ const start = Date.now();
440
+ const originalEnd = res.end.bind(res);
441
+ res.end = ((...args) => {
442
+ const url = new URL(req.url, "http://localhost");
443
+ cipher.logRequest({
444
+ method: req.method,
445
+ path: url.pathname + url.search,
446
+ status: res.status ?? 200,
447
+ duration: Date.now() - start,
448
+ ip: getHeader7(req, "x-forwarded-for")?.split(",")[0]?.trim() ?? getHeader7(req, "x-real-ip"),
449
+ userAgent: getHeader7(req, "user-agent"),
450
+ referer: getHeader7(req, "referer"),
451
+ protocol: url.protocol.replace(":", ""),
452
+ host: getHeader7(req, "host"),
453
+ query: parseQuery7(url),
454
+ requestId: getHeader7(req, "x-request-id")
455
+ });
456
+ return originalEnd(...args);
457
+ });
458
+ };
459
+ }
460
+
461
+ // src/adapters/nuxt/middleware.ts
462
+ function getHeader8(request, name) {
463
+ if (request.headers instanceof Headers) {
464
+ return request.headers.get(name) ?? void 0;
465
+ }
466
+ const value = request.headers[name.toLowerCase()];
467
+ if (Array.isArray(value)) {
468
+ return value[0];
469
+ }
470
+ return value ?? void 0;
471
+ }
472
+ function parseQuery8(url) {
473
+ const result = {};
474
+ for (const [key, value] of url.searchParams.entries()) {
475
+ result[key] = value;
476
+ }
477
+ return Object.keys(result).length > 0 ? result : void 0;
478
+ }
479
+ function createNuxtMiddleware(cipher) {
480
+ return (req, res) => {
481
+ const start = Date.now();
482
+ const originalEnd = res.end.bind(res);
483
+ res.end = ((...args) => {
484
+ const url = new URL(req.url, "http://localhost");
485
+ cipher.logRequest({
486
+ method: req.method,
487
+ path: url.pathname + url.search,
488
+ status: res.status ?? 200,
489
+ duration: Date.now() - start,
490
+ ip: getHeader8(req, "x-forwarded-for")?.split(",")[0]?.trim() ?? getHeader8(req, "x-real-ip"),
491
+ userAgent: getHeader8(req, "user-agent"),
492
+ referer: getHeader8(req, "referer"),
493
+ protocol: url.protocol.replace(":", ""),
494
+ host: getHeader8(req, "host"),
495
+ query: parseQuery8(url),
496
+ requestId: getHeader8(req, "x-request-id")
497
+ });
498
+ return originalEnd(...args);
499
+ });
500
+ };
501
+ }
502
+
369
503
  // src/core/create-cipher-logger.ts
370
504
  function createCipherLogger(config = {}) {
371
505
  const fields = resolveFieldConfig(config.fields);
@@ -385,6 +519,15 @@ function createCipherLogger(config = {}) {
385
519
  next() {
386
520
  return createNextMiddleware(cipherLogger);
387
521
  },
522
+ react() {
523
+ return createReactMiddleware(cipherLogger);
524
+ },
525
+ vue() {
526
+ return createVueMiddleware(cipherLogger);
527
+ },
528
+ nuxt() {
529
+ return createNuxtMiddleware(cipherLogger);
530
+ },
388
531
  fastify() {
389
532
  return createFastifyMiddleware(cipherLogger);
390
533
  },
@@ -409,5 +552,8 @@ var logger = new Logger();
409
552
  createHonoMiddleware,
410
553
  createNestMiddleware,
411
554
  createNextMiddleware,
555
+ createNuxtMiddleware,
556
+ createReactMiddleware,
557
+ createVueMiddleware,
412
558
  logger
413
559
  });
package/dist/index.mjs CHANGED
@@ -279,7 +279,9 @@ function createNestMiddleware(cipher) {
279
279
 
280
280
  // src/adapters/hono/middleware.ts
281
281
  function getHeader5(request, name) {
282
- if (!request) return void 0;
282
+ if (!request) {
283
+ return void 0;
284
+ }
283
285
  if (typeof request.header === "function") {
284
286
  return request.header(name) ?? void 0;
285
287
  }
@@ -288,6 +290,9 @@ function getHeader5(request, name) {
288
290
  }
289
291
  return void 0;
290
292
  }
293
+ function hasHeader(request, name) {
294
+ return Boolean(getHeader5(request, name));
295
+ }
291
296
  function parseQuery5(urlString) {
292
297
  try {
293
298
  const url = new URL(urlString);
@@ -315,7 +320,7 @@ function createHonoMiddleware(cipher) {
315
320
  status = cres.statusCode;
316
321
  }
317
322
  const xfwd = getHeader5(req, "x-forwarded-for");
318
- const ip = xfwd ? String(xfwd).split(",")[0].trim() : getHeader5(req, "x-real-ip") ?? void 0;
323
+ const ip = hasHeader(req, "x-forwarded-for") ? String(xfwd).split(",")[0].trim() : getHeader5(req, "x-real-ip") ?? void 0;
319
324
  cipher.logRequest({
320
325
  method: req?.method,
321
326
  path: parsed.pathname + parsed.search,
@@ -333,6 +338,132 @@ function createHonoMiddleware(cipher) {
333
338
  };
334
339
  }
335
340
 
341
+ // src/adapters/react/middleware.ts
342
+ function getHeader6(request, name) {
343
+ if (request.headers instanceof Headers) {
344
+ return request.headers.get(name) ?? void 0;
345
+ }
346
+ const value = request.headers[name.toLowerCase()];
347
+ if (Array.isArray(value)) {
348
+ return value[0];
349
+ }
350
+ return value ?? void 0;
351
+ }
352
+ function parseQuery6(url) {
353
+ const result = {};
354
+ for (const [key, value] of url.searchParams.entries()) {
355
+ result[key] = value;
356
+ }
357
+ return Object.keys(result).length > 0 ? result : void 0;
358
+ }
359
+ function createReactMiddleware(cipher) {
360
+ return (req, res) => {
361
+ const start = Date.now();
362
+ const originalEnd = res.end.bind(res);
363
+ res.end = ((...args) => {
364
+ const url = new URL(req.url, "http://localhost");
365
+ cipher.logRequest({
366
+ method: req.method,
367
+ path: url.pathname + url.search,
368
+ status: res.status ?? 200,
369
+ duration: Date.now() - start,
370
+ ip: getHeader6(req, "x-forwarded-for")?.split(",")[0]?.trim() ?? getHeader6(req, "x-real-ip"),
371
+ userAgent: getHeader6(req, "user-agent"),
372
+ referer: getHeader6(req, "referer"),
373
+ protocol: url.protocol.replace(":", ""),
374
+ host: getHeader6(req, "host"),
375
+ query: parseQuery6(url),
376
+ requestId: getHeader6(req, "x-request-id")
377
+ });
378
+ return originalEnd(...args);
379
+ });
380
+ };
381
+ }
382
+
383
+ // src/adapters/vue/middleware.ts
384
+ function getHeader7(request, name) {
385
+ if (request.headers instanceof Headers) {
386
+ return request.headers.get(name) ?? void 0;
387
+ }
388
+ const value = request.headers[name.toLowerCase()];
389
+ if (Array.isArray(value)) {
390
+ return value[0];
391
+ }
392
+ return value ?? void 0;
393
+ }
394
+ function parseQuery7(url) {
395
+ const result = {};
396
+ for (const [key, value] of url.searchParams.entries()) {
397
+ result[key] = value;
398
+ }
399
+ return Object.keys(result).length > 0 ? result : void 0;
400
+ }
401
+ function createVueMiddleware(cipher) {
402
+ return (req, res) => {
403
+ const start = Date.now();
404
+ const originalEnd = res.end.bind(res);
405
+ res.end = ((...args) => {
406
+ const url = new URL(req.url, "http://localhost");
407
+ cipher.logRequest({
408
+ method: req.method,
409
+ path: url.pathname + url.search,
410
+ status: res.status ?? 200,
411
+ duration: Date.now() - start,
412
+ ip: getHeader7(req, "x-forwarded-for")?.split(",")[0]?.trim() ?? getHeader7(req, "x-real-ip"),
413
+ userAgent: getHeader7(req, "user-agent"),
414
+ referer: getHeader7(req, "referer"),
415
+ protocol: url.protocol.replace(":", ""),
416
+ host: getHeader7(req, "host"),
417
+ query: parseQuery7(url),
418
+ requestId: getHeader7(req, "x-request-id")
419
+ });
420
+ return originalEnd(...args);
421
+ });
422
+ };
423
+ }
424
+
425
+ // src/adapters/nuxt/middleware.ts
426
+ function getHeader8(request, name) {
427
+ if (request.headers instanceof Headers) {
428
+ return request.headers.get(name) ?? void 0;
429
+ }
430
+ const value = request.headers[name.toLowerCase()];
431
+ if (Array.isArray(value)) {
432
+ return value[0];
433
+ }
434
+ return value ?? void 0;
435
+ }
436
+ function parseQuery8(url) {
437
+ const result = {};
438
+ for (const [key, value] of url.searchParams.entries()) {
439
+ result[key] = value;
440
+ }
441
+ return Object.keys(result).length > 0 ? result : void 0;
442
+ }
443
+ function createNuxtMiddleware(cipher) {
444
+ return (req, res) => {
445
+ const start = Date.now();
446
+ const originalEnd = res.end.bind(res);
447
+ res.end = ((...args) => {
448
+ const url = new URL(req.url, "http://localhost");
449
+ cipher.logRequest({
450
+ method: req.method,
451
+ path: url.pathname + url.search,
452
+ status: res.status ?? 200,
453
+ duration: Date.now() - start,
454
+ ip: getHeader8(req, "x-forwarded-for")?.split(",")[0]?.trim() ?? getHeader8(req, "x-real-ip"),
455
+ userAgent: getHeader8(req, "user-agent"),
456
+ referer: getHeader8(req, "referer"),
457
+ protocol: url.protocol.replace(":", ""),
458
+ host: getHeader8(req, "host"),
459
+ query: parseQuery8(url),
460
+ requestId: getHeader8(req, "x-request-id")
461
+ });
462
+ return originalEnd(...args);
463
+ });
464
+ };
465
+ }
466
+
336
467
  // src/core/create-cipher-logger.ts
337
468
  function createCipherLogger(config = {}) {
338
469
  const fields = resolveFieldConfig(config.fields);
@@ -352,6 +483,15 @@ function createCipherLogger(config = {}) {
352
483
  next() {
353
484
  return createNextMiddleware(cipherLogger);
354
485
  },
486
+ react() {
487
+ return createReactMiddleware(cipherLogger);
488
+ },
489
+ vue() {
490
+ return createVueMiddleware(cipherLogger);
491
+ },
492
+ nuxt() {
493
+ return createNuxtMiddleware(cipherLogger);
494
+ },
355
495
  fastify() {
356
496
  return createFastifyMiddleware(cipherLogger);
357
497
  },
@@ -375,5 +515,8 @@ export {
375
515
  createHonoMiddleware,
376
516
  createNestMiddleware,
377
517
  createNextMiddleware,
518
+ createNuxtMiddleware,
519
+ createReactMiddleware,
520
+ createVueMiddleware,
378
521
  logger
379
522
  };
@@ -0,0 +1,69 @@
1
+ import { defineConfig, globalIgnores } from "eslint/config";
2
+ import nextVitals from "eslint-config-next/core-web-vitals";
3
+ import nextTs from "eslint-config-next/typescript";
4
+
5
+ export default defineConfig([
6
+ ...nextVitals,
7
+ ...nextTs,
8
+
9
+ {
10
+ rules: {
11
+ // ===== JavaScript =====
12
+ eqeqeq: ["error", "always"],
13
+ curly: ["error", "all"],
14
+ "no-var": "error",
15
+ "prefer-const": "error",
16
+ "no-console":
17
+ process.env.NODE_ENV === "production"
18
+ ? ["warn", { allow: ["warn", "error"] }]
19
+ : "off",
20
+
21
+ // ===== TypeScript =====
22
+ "@typescript-eslint/no-unused-vars": [
23
+ "warn",
24
+ {
25
+ argsIgnorePattern: "^_",
26
+ varsIgnorePattern: "^_",
27
+ ignoreRestSiblings: true,
28
+ },
29
+ ],
30
+ "@typescript-eslint/consistent-type-imports": [
31
+ "error",
32
+ {
33
+ prefer: "type-imports",
34
+ fixStyle: "inline-type-imports",
35
+ },
36
+ ],
37
+ "@typescript-eslint/no-explicit-any": "warn",
38
+ "@typescript-eslint/no-non-null-assertion": "warn",
39
+
40
+ // ===== Import =====
41
+ "sort-imports": [
42
+ "warn",
43
+ {
44
+ ignoreDeclarationSort: true,
45
+ ignoreCase: true,
46
+ },
47
+ ],
48
+
49
+ // ===== React =====
50
+ "react/jsx-key": "error",
51
+ "react/self-closing-comp": "warn",
52
+
53
+ // ===== Next =====
54
+ "@next/next/no-img-element": "warn",
55
+ },
56
+ },
57
+
58
+ globalIgnores([
59
+ ".next/**",
60
+ "out/**",
61
+ "build/**",
62
+ "next-env.d.ts",
63
+ "coverage/**",
64
+ "dist/**",
65
+ "*.config.js",
66
+ "*.config.cjs",
67
+ "*.config.mjs",
68
+ ]),
69
+ ]);
package/package.json CHANGED
@@ -1,13 +1,19 @@
1
1
  {
2
2
  "name": "cipher-logger",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "See every request. Capture every error. Understand your application.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
7
7
  "types": "./dist/index.d.ts",
8
8
  "scripts": {
9
9
  "build": "tsup",
10
- "prepublishOnly": "npm run build"
10
+ "lint": "eslint .",
11
+ "lint:fix": "eslint --fix .",
12
+ "test": "pnpm run lint && pnpm run build",
13
+ "prepublishOnly": "pnpm run test",
14
+ "commitlint": "commitlint --edit",
15
+ "clean": "rm -rf out dist node_modules/.cache",
16
+ "prepare": "husky"
11
17
  },
12
18
  "repository": {
13
19
  "type": "git",
@@ -41,6 +47,12 @@
41
47
  "nextjs",
42
48
  "nextjs-logger",
43
49
  "nextjs-middleware",
50
+ "react",
51
+ "react-logger",
52
+ "vue",
53
+ "vue-logger",
54
+ "nuxt",
55
+ "nuxt-logger",
44
56
  "express",
45
57
  "express-logger",
46
58
  "fastify",
@@ -62,6 +74,9 @@
62
74
  "peerDependencies": {
63
75
  "express": ">=4",
64
76
  "next": ">=13",
77
+ "react": ">=18",
78
+ "vue": ">=3",
79
+ "nuxt": ">=3",
65
80
  "fastify": ">=4",
66
81
  "hono": ">=1",
67
82
  "@nestjs/common": ">=10",
@@ -73,8 +88,16 @@
73
88
  },
74
89
  "next": {
75
90
  "optional": true
76
- }
77
- ,
91
+ },
92
+ "react": {
93
+ "optional": true
94
+ },
95
+ "vue": {
96
+ "optional": true
97
+ },
98
+ "nuxt": {
99
+ "optional": true
100
+ },
78
101
  "fastify": {
79
102
  "optional": true
80
103
  },
@@ -89,6 +112,8 @@
89
112
  }
90
113
  },
91
114
  "devDependencies": {
115
+ "@commitlint/cli": "^20.1.0",
116
+ "@commitlint/config-conventional": "^20.0.0",
92
117
  "@types/express": "^5.0.3",
93
118
  "@types/node": "^26.1.2",
94
119
  "express": "^5.1.0",
@@ -96,6 +121,9 @@
96
121
  "fastify": "^4.27.0",
97
122
  "hono": "^3.3.0",
98
123
  "tsup": "^8.5.1",
124
+ "eslint": "^9",
125
+ "eslint-config-next": "16.3.0",
126
+ "husky": "^9.1.7",
99
127
  "typescript": "^6.0.3"
100
128
  }
101
- }
129
+ }
@@ -0,0 +1,18 @@
1
+ /** @type {import("prettier").Config} */
2
+ const config = {
3
+ semi: true,
4
+ singleQuote: false,
5
+ jsxSingleQuote: false,
6
+ trailingComma: "all",
7
+ tabWidth: 2,
8
+ useTabs: false,
9
+ printWidth: 80,
10
+ bracketSpacing: true,
11
+ bracketSameLine: false,
12
+ arrowParens: "always",
13
+ endOfLine: "lf",
14
+
15
+ plugins: ["prettier-plugin-tailwindcss"],
16
+ };
17
+
18
+ export default config;