snapwyr 1.0.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/README.md +420 -0
- package/dist/dashboard.d.mts +1 -0
- package/dist/dashboard.d.ts +1 -0
- package/dist/dashboard.js +35 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/dashboard.mjs +8 -0
- package/dist/dashboard.mjs.map +1 -0
- package/dist/express.d.mts +26 -0
- package/dist/express.d.ts +26 -0
- package/dist/express.js +203 -0
- package/dist/express.js.map +1 -0
- package/dist/express.mjs +183 -0
- package/dist/express.mjs.map +1 -0
- package/dist/fastify.d.mts +13 -0
- package/dist/fastify.d.ts +13 -0
- package/dist/fastify.js +204 -0
- package/dist/fastify.js.map +1 -0
- package/dist/fastify.mjs +184 -0
- package/dist/fastify.mjs.map +1 -0
- package/dist/hono.d.mts +18 -0
- package/dist/hono.d.ts +18 -0
- package/dist/hono.js +190 -0
- package/dist/hono.js.map +1 -0
- package/dist/hono.mjs +170 -0
- package/dist/hono.mjs.map +1 -0
- package/dist/index.d.mts +28 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +78 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +51 -0
- package/dist/index.mjs.map +1 -0
- package/dist/koa.d.mts +21 -0
- package/dist/koa.d.ts +21 -0
- package/dist/koa.js +185 -0
- package/dist/koa.js.map +1 -0
- package/dist/koa.mjs +165 -0
- package/dist/koa.mjs.map +1 -0
- package/dist/nestjs.d.mts +19 -0
- package/dist/nestjs.d.ts +19 -0
- package/dist/nestjs.js +211 -0
- package/dist/nestjs.js.map +1 -0
- package/dist/nestjs.mjs +191 -0
- package/dist/nestjs.mjs.map +1 -0
- package/dist/nextjs.d.mts +33 -0
- package/dist/nextjs.d.ts +33 -0
- package/dist/nextjs.js +191 -0
- package/dist/nextjs.js.map +1 -0
- package/dist/nextjs.mjs +178 -0
- package/dist/nextjs.mjs.map +1 -0
- package/package.json +174 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hono.ts","../src/utils.ts"],"sourcesContent":["import type { SnapWyrConfig, LogEntry } from '@snapwyr/core';\nimport { generateRequestId } from '@snapwyr/core';\nimport { logRequest } from './utils.js';\n\ninterface HonoContext {\n req: {\n method: string;\n path: string;\n query: (key?: string) => string | Record<string, string> | undefined;\n raw: Request;\n };\n res: Response | undefined;\n header: (name: string, value: string) => void;\n}\ntype HonoNext = () => Promise<void>;\ntype HonoMiddleware = (\n c: HonoContext,\n next: HonoNext\n) => Promise<Response | void>;\n\nexport function snapwyr(config: SnapWyrConfig = {}): HonoMiddleware {\n return async function (c, next) {\n if (config.enabled === false) {\n await next();\n return;\n }\n\n const id = generateRequestId();\n const startTime = Date.now();\n const method = c.req.method;\n const queryObj = c.req.query();\n const queryString =\n typeof queryObj === 'object' && queryObj\n ? new URLSearchParams(queryObj as Record<string, string>).toString()\n : '';\n const url = c.req.path + (queryString ? '?' + queryString : '');\n\n if (config.requestId)\n try {\n c.header('X-Request-ID', id);\n } catch {}\n\n let requestBody: string | undefined;\n if (config.logBody) {\n try {\n const body = await c.req.raw\n .clone()\n .text()\n .catch(() => null);\n if (body) requestBody = body.slice(0, config.bodySizeLimit || 500);\n } catch {}\n }\n\n await next();\n\n const duration = Date.now() - startTime;\n const status = c.res?.status ?? 200;\n\n if (\n config.statusCodes &&\n config.statusCodes.length > 0 &&\n !config.statusCodes.includes(status)\n )\n return;\n\n let responseBody: string | undefined;\n if (config.logBody && c.res) {\n try {\n const resBody = await c.res\n .clone()\n .text()\n .catch(() => null);\n if (resBody)\n responseBody = resBody.slice(0, config.bodySizeLimit || 500);\n } catch {}\n }\n\n logRequest({\n id,\n method,\n status,\n duration,\n url,\n startTime,\n config,\n requestBody: config.logBody ? requestBody : undefined,\n responseBody: config.logBody ? responseBody : undefined,\n });\n };\n}\n\nexport type { SnapWyrConfig, LogEntry };\n","import type { SnapWyrConfig, LogEntry } from '@snapwyr/core';\nimport {\n snapwyr as coreEmitter,\n getByteSize,\n formatBytes,\n redactSensitiveData,\n} from '@snapwyr/core';\n\nexport interface LogParams {\n id: string;\n method: string;\n status: number;\n duration: number;\n url: string;\n startTime: number;\n config: SnapWyrConfig;\n requestBody?: string;\n responseBody?: string;\n error?: string;\n}\n\nexport function logRequest(params: LogParams): void {\n const { id, method, status, duration, url, startTime, config, error } =\n params;\n let { requestBody, responseBody } = params;\n\n if (config.silent) return;\n\n const showTimestamp = config.showTimestamp !== false;\n const format = config.format || 'pretty';\n const slowThreshold = config.slowThreshold ?? 1000;\n const isSlow = duration >= slowThreshold;\n\n const requestSize = requestBody ? getByteSize(requestBody) : 0;\n const responseSize = responseBody ? getByteSize(responseBody) : 0;\n const totalSize = requestSize + responseSize;\n\n if (config.redact && config.redact.length > 0) {\n if (requestBody)\n requestBody = redactSensitiveData(requestBody, config.redact);\n if (responseBody)\n responseBody = redactSensitiveData(responseBody, config.redact);\n }\n\n const logEntry: LogEntry = {\n id,\n timestamp: new Date(startTime).toISOString(),\n method: method.toUpperCase(),\n url,\n status,\n duration,\n slow: isSlow,\n };\n\n if (config.prefix) logEntry.prefix = config.prefix;\n if (error) logEntry.error = error;\n if (requestBody) logEntry.requestBody = requestBody;\n if (responseBody) logEntry.responseBody = responseBody;\n if (config.sizeTracking) {\n logEntry.requestSize = requestSize;\n logEntry.responseSize = responseSize;\n logEntry.totalSize = totalSize;\n }\n\n try {\n coreEmitter.emit('request', {\n id,\n method: method.toUpperCase(),\n url,\n status,\n duration,\n timestamp: startTime,\n requestBody,\n responseBody,\n error,\n requestSize: config.sizeTracking ? requestSize : undefined,\n responseSize: config.sizeTracking ? responseSize : undefined,\n direction: 'incoming',\n });\n } catch {}\n\n if (config.transport) {\n config.transport(logEntry);\n }\n\n if (format === 'json') {\n console.log(JSON.stringify(logEntry));\n return;\n }\n\n const useEmoji = config.emoji === true;\n let statusEmoji = '';\n if (useEmoji) {\n if (error || status >= 500) statusEmoji = '✗ ';\n else if (status >= 400) statusEmoji = '⚠ ';\n else if (status >= 300) statusEmoji = '↪ ';\n else statusEmoji = '✓ ';\n }\n\n const statusColor =\n status >= 500\n ? '\\x1b[31m'\n : status >= 400\n ? '\\x1b[33m'\n : status >= 300\n ? '\\x1b[36m'\n : '\\x1b[32m';\n const durationColor = isSlow\n ? '\\x1b[31m'\n : duration < 100\n ? '\\x1b[32m'\n : '\\x1b[33m';\n const methodColors: Record<string, string> = {\n GET: '\\x1b[34m',\n POST: '\\x1b[32m',\n PUT: '\\x1b[33m',\n PATCH: '\\x1b[35m',\n DELETE: '\\x1b[31m',\n };\n const methodColor = methodColors[method] || '';\n const reset = '\\x1b[0m';\n const dim = '\\x1b[2m';\n const bold = '\\x1b[1m';\n const timestamp = showTimestamp\n ? new Date(startTime).toISOString().slice(11, 23) + ' '\n : '';\n const slowIndicator = isSlow ? ` ${bold}[SLOW]${reset}` : '';\n const requestIdDisplay = config.requestId ? `${dim}[${id}]${reset} ` : '';\n const sizeDisplay = config.sizeTracking\n ? `${dim}${formatBytes(totalSize)}${reset} `\n : '';\n\n const parts = [\n config.prefix ? `${dim}${config.prefix} ${reset}` : '',\n requestIdDisplay,\n `${dim}${timestamp}${reset}`,\n `${methodColor}${method.padEnd(6)}${reset}`,\n `${statusColor}${statusEmoji}${status}${reset}`,\n `${durationColor}${duration}ms${reset}${slowIndicator}`,\n sizeDisplay,\n `${dim}${url}${reset}`,\n ].filter(Boolean);\n\n if (error) parts.push(`\\n ${dim}Error: ${error}${reset}`);\n if (requestBody) parts.push(`\\n ${dim}Request: ${requestBody}${reset}`);\n if (responseBody) parts.push(`\\n ${dim}Response: ${responseBody}${reset}`);\n\n console.log(parts.join(' '));\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { SnapWyrConfig } from '@snapwyr/core';
|
|
2
|
+
export { LogEntry, RequestEvent, SnapWyrConfig, TransportFn, formatBytes, generateRequestId as generateRequestIdFromCore, getByteSize, redactSensitiveData, toCurl as toCurlFromCore } from '@snapwyr/core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { logRequests } from 'snapwyr';
|
|
8
|
+
* logRequests();
|
|
9
|
+
* logRequests({ format: 'json', emoji: true });
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
declare function logRequests(config?: SnapWyrConfig): void;
|
|
13
|
+
declare function stopLogging(): void;
|
|
14
|
+
/**
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const curl = toCurl({ method: 'POST', url: '...', headers: {...}, body: '...' });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
declare function toCurl(params: {
|
|
21
|
+
method: string;
|
|
22
|
+
url: string;
|
|
23
|
+
headers?: Record<string, string>;
|
|
24
|
+
body?: string;
|
|
25
|
+
}): string;
|
|
26
|
+
declare function generateRequestId(): string;
|
|
27
|
+
|
|
28
|
+
export { generateRequestId, logRequests, stopLogging, toCurl };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { SnapWyrConfig } from '@snapwyr/core';
|
|
2
|
+
export { LogEntry, RequestEvent, SnapWyrConfig, TransportFn, formatBytes, generateRequestId as generateRequestIdFromCore, getByteSize, redactSensitiveData, toCurl as toCurlFromCore } from '@snapwyr/core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { logRequests } from 'snapwyr';
|
|
8
|
+
* logRequests();
|
|
9
|
+
* logRequests({ format: 'json', emoji: true });
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
declare function logRequests(config?: SnapWyrConfig): void;
|
|
13
|
+
declare function stopLogging(): void;
|
|
14
|
+
/**
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const curl = toCurl({ method: 'POST', url: '...', headers: {...}, body: '...' });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
declare function toCurl(params: {
|
|
21
|
+
method: string;
|
|
22
|
+
url: string;
|
|
23
|
+
headers?: Record<string, string>;
|
|
24
|
+
body?: string;
|
|
25
|
+
}): string;
|
|
26
|
+
declare function generateRequestId(): string;
|
|
27
|
+
|
|
28
|
+
export { generateRequestId, logRequests, stopLogging, toCurl };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
formatBytes: () => import_core2.formatBytes,
|
|
24
|
+
generateRequestId: () => generateRequestId2,
|
|
25
|
+
generateRequestIdFromCore: () => import_core2.generateRequestId,
|
|
26
|
+
getByteSize: () => import_core2.getByteSize,
|
|
27
|
+
logRequests: () => logRequests,
|
|
28
|
+
redactSensitiveData: () => import_core2.redactSensitiveData,
|
|
29
|
+
stopLogging: () => stopLogging,
|
|
30
|
+
toCurl: () => toCurl2,
|
|
31
|
+
toCurlFromCore: () => import_core2.toCurl
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(index_exports);
|
|
34
|
+
var import_core = require("@snapwyr/core");
|
|
35
|
+
var import_core2 = require("@snapwyr/core");
|
|
36
|
+
function logRequests(config = {}) {
|
|
37
|
+
import_core.snapwyr.start(config);
|
|
38
|
+
}
|
|
39
|
+
function stopLogging() {
|
|
40
|
+
import_core.snapwyr.stop();
|
|
41
|
+
}
|
|
42
|
+
function toCurl2(params) {
|
|
43
|
+
const { method, url, headers, body } = params;
|
|
44
|
+
const parts = ["curl"];
|
|
45
|
+
if (method.toUpperCase() !== "GET") {
|
|
46
|
+
parts.push(`-X ${method.toUpperCase()}`);
|
|
47
|
+
}
|
|
48
|
+
if (headers) {
|
|
49
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
50
|
+
if (key.startsWith(":") || key.toLowerCase() === "authorization") {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
parts.push(`-H '${key}: ${value}'`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (body && method.toUpperCase() !== "GET") {
|
|
57
|
+
const escapedBody = body.replace(/'/g, "'\\''");
|
|
58
|
+
parts.push(`-d '${escapedBody}'`);
|
|
59
|
+
}
|
|
60
|
+
parts.push(`'${url}'`);
|
|
61
|
+
return parts.join(" \\\n ");
|
|
62
|
+
}
|
|
63
|
+
function generateRequestId2() {
|
|
64
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 9)}`;
|
|
65
|
+
}
|
|
66
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
67
|
+
0 && (module.exports = {
|
|
68
|
+
formatBytes,
|
|
69
|
+
generateRequestId,
|
|
70
|
+
generateRequestIdFromCore,
|
|
71
|
+
getByteSize,
|
|
72
|
+
logRequests,
|
|
73
|
+
redactSensitiveData,
|
|
74
|
+
stopLogging,
|
|
75
|
+
toCurl,
|
|
76
|
+
toCurlFromCore
|
|
77
|
+
});
|
|
78
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { snapwyr, SnapWyrConfig } from '@snapwyr/core';\n\n/**\n * @example\n * ```ts\n * import { logRequests } from 'snapwyr';\n * logRequests();\n * logRequests({ format: 'json', emoji: true });\n * ```\n */\nexport function logRequests(config: SnapWyrConfig = {}): void {\n snapwyr.start(config);\n}\n\nexport function stopLogging(): void {\n snapwyr.stop();\n}\n\n/**\n * @example\n * ```ts\n * const curl = toCurl({ method: 'POST', url: '...', headers: {...}, body: '...' });\n * ```\n */\nexport function toCurl(params: {\n method: string;\n url: string;\n headers?: Record<string, string>;\n body?: string;\n}): string {\n const { method, url, headers, body } = params;\n const parts = ['curl'];\n\n if (method.toUpperCase() !== 'GET') {\n parts.push(`-X ${method.toUpperCase()}`);\n }\n\n if (headers) {\n for (const [key, value] of Object.entries(headers)) {\n if (key.startsWith(':') || key.toLowerCase() === 'authorization') {\n continue;\n }\n parts.push(`-H '${key}: ${value}'`);\n }\n }\n\n if (body && method.toUpperCase() !== 'GET') {\n const escapedBody = body.replace(/'/g, \"'\\\\''\");\n parts.push(`-d '${escapedBody}'`);\n }\n\n parts.push(`'${url}'`);\n\n return parts.join(' \\\\\\n ');\n}\n\nexport function generateRequestId(): string {\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 9)}`;\n}\n\nexport {\n toCurl as toCurlFromCore,\n generateRequestId as generateRequestIdFromCore,\n redactSensitiveData,\n formatBytes,\n getByteSize,\n} from '@snapwyr/core';\nexport type {\n SnapWyrConfig,\n RequestEvent,\n LogEntry,\n TransportFn,\n} from '@snapwyr/core';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA,2BAAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAAC;AAAA,EAAA;AAAA;AAAA;AAAA,kBAAuC;AA4DvC,IAAAC,eAMO;AAxDA,SAAS,YAAY,SAAwB,CAAC,GAAS;AAC5D,sBAAQ,MAAM,MAAM;AACtB;AAEO,SAAS,cAAoB;AAClC,sBAAQ,KAAK;AACf;AAQO,SAASD,QAAO,QAKZ;AACT,QAAM,EAAE,QAAQ,KAAK,SAAS,KAAK,IAAI;AACvC,QAAM,QAAQ,CAAC,MAAM;AAErB,MAAI,OAAO,YAAY,MAAM,OAAO;AAClC,UAAM,KAAK,MAAM,OAAO,YAAY,CAAC,EAAE;AAAA,EACzC;AAEA,MAAI,SAAS;AACX,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,UAAI,IAAI,WAAW,GAAG,KAAK,IAAI,YAAY,MAAM,iBAAiB;AAChE;AAAA,MACF;AACA,YAAM,KAAK,OAAO,GAAG,KAAK,KAAK,GAAG;AAAA,IACpC;AAAA,EACF;AAEA,MAAI,QAAQ,OAAO,YAAY,MAAM,OAAO;AAC1C,UAAM,cAAc,KAAK,QAAQ,MAAM,OAAO;AAC9C,UAAM,KAAK,OAAO,WAAW,GAAG;AAAA,EAClC;AAEA,QAAM,KAAK,IAAI,GAAG,GAAG;AAErB,SAAO,MAAM,KAAK,SAAS;AAC7B;AAEO,SAASD,qBAA4B;AAC1C,SAAO,GAAG,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAC7E;","names":["generateRequestId","toCurl","import_core"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { snapwyr } from "@snapwyr/core";
|
|
3
|
+
import {
|
|
4
|
+
toCurl,
|
|
5
|
+
generateRequestId,
|
|
6
|
+
redactSensitiveData,
|
|
7
|
+
formatBytes,
|
|
8
|
+
getByteSize
|
|
9
|
+
} from "@snapwyr/core";
|
|
10
|
+
function logRequests(config = {}) {
|
|
11
|
+
snapwyr.start(config);
|
|
12
|
+
}
|
|
13
|
+
function stopLogging() {
|
|
14
|
+
snapwyr.stop();
|
|
15
|
+
}
|
|
16
|
+
function toCurl2(params) {
|
|
17
|
+
const { method, url, headers, body } = params;
|
|
18
|
+
const parts = ["curl"];
|
|
19
|
+
if (method.toUpperCase() !== "GET") {
|
|
20
|
+
parts.push(`-X ${method.toUpperCase()}`);
|
|
21
|
+
}
|
|
22
|
+
if (headers) {
|
|
23
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
24
|
+
if (key.startsWith(":") || key.toLowerCase() === "authorization") {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
parts.push(`-H '${key}: ${value}'`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (body && method.toUpperCase() !== "GET") {
|
|
31
|
+
const escapedBody = body.replace(/'/g, "'\\''");
|
|
32
|
+
parts.push(`-d '${escapedBody}'`);
|
|
33
|
+
}
|
|
34
|
+
parts.push(`'${url}'`);
|
|
35
|
+
return parts.join(" \\\n ");
|
|
36
|
+
}
|
|
37
|
+
function generateRequestId2() {
|
|
38
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 9)}`;
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
formatBytes,
|
|
42
|
+
generateRequestId2 as generateRequestId,
|
|
43
|
+
generateRequestId as generateRequestIdFromCore,
|
|
44
|
+
getByteSize,
|
|
45
|
+
logRequests,
|
|
46
|
+
redactSensitiveData,
|
|
47
|
+
stopLogging,
|
|
48
|
+
toCurl2 as toCurl,
|
|
49
|
+
toCurl as toCurlFromCore
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { snapwyr, SnapWyrConfig } from '@snapwyr/core';\n\n/**\n * @example\n * ```ts\n * import { logRequests } from 'snapwyr';\n * logRequests();\n * logRequests({ format: 'json', emoji: true });\n * ```\n */\nexport function logRequests(config: SnapWyrConfig = {}): void {\n snapwyr.start(config);\n}\n\nexport function stopLogging(): void {\n snapwyr.stop();\n}\n\n/**\n * @example\n * ```ts\n * const curl = toCurl({ method: 'POST', url: '...', headers: {...}, body: '...' });\n * ```\n */\nexport function toCurl(params: {\n method: string;\n url: string;\n headers?: Record<string, string>;\n body?: string;\n}): string {\n const { method, url, headers, body } = params;\n const parts = ['curl'];\n\n if (method.toUpperCase() !== 'GET') {\n parts.push(`-X ${method.toUpperCase()}`);\n }\n\n if (headers) {\n for (const [key, value] of Object.entries(headers)) {\n if (key.startsWith(':') || key.toLowerCase() === 'authorization') {\n continue;\n }\n parts.push(`-H '${key}: ${value}'`);\n }\n }\n\n if (body && method.toUpperCase() !== 'GET') {\n const escapedBody = body.replace(/'/g, \"'\\\\''\");\n parts.push(`-d '${escapedBody}'`);\n }\n\n parts.push(`'${url}'`);\n\n return parts.join(' \\\\\\n ');\n}\n\nexport function generateRequestId(): string {\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 9)}`;\n}\n\nexport {\n toCurl as toCurlFromCore,\n generateRequestId as generateRequestIdFromCore,\n redactSensitiveData,\n formatBytes,\n getByteSize,\n} from '@snapwyr/core';\nexport type {\n SnapWyrConfig,\n RequestEvent,\n LogEntry,\n TransportFn,\n} from '@snapwyr/core';\n"],"mappings":";AAAA,SAAS,eAA8B;AA4DvC;AAAA,EACY;AAAA,EACW;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAxDA,SAAS,YAAY,SAAwB,CAAC,GAAS;AAC5D,UAAQ,MAAM,MAAM;AACtB;AAEO,SAAS,cAAoB;AAClC,UAAQ,KAAK;AACf;AAQO,SAASA,QAAO,QAKZ;AACT,QAAM,EAAE,QAAQ,KAAK,SAAS,KAAK,IAAI;AACvC,QAAM,QAAQ,CAAC,MAAM;AAErB,MAAI,OAAO,YAAY,MAAM,OAAO;AAClC,UAAM,KAAK,MAAM,OAAO,YAAY,CAAC,EAAE;AAAA,EACzC;AAEA,MAAI,SAAS;AACX,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,UAAI,IAAI,WAAW,GAAG,KAAK,IAAI,YAAY,MAAM,iBAAiB;AAChE;AAAA,MACF;AACA,YAAM,KAAK,OAAO,GAAG,KAAK,KAAK,GAAG;AAAA,IACpC;AAAA,EACF;AAEA,MAAI,QAAQ,OAAO,YAAY,MAAM,OAAO;AAC1C,UAAM,cAAc,KAAK,QAAQ,MAAM,OAAO;AAC9C,UAAM,KAAK,OAAO,WAAW,GAAG;AAAA,EAClC;AAEA,QAAM,KAAK,IAAI,GAAG,GAAG;AAErB,SAAO,MAAM,KAAK,SAAS;AAC7B;AAEO,SAASC,qBAA4B;AAC1C,SAAO,GAAG,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAC7E;","names":["toCurl","generateRequestId"]}
|
package/dist/koa.d.mts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SnapWyrConfig } from '@snapwyr/core';
|
|
2
|
+
export { LogEntry, SnapWyrConfig } from '@snapwyr/core';
|
|
3
|
+
|
|
4
|
+
interface KoaRequest {
|
|
5
|
+
method: string;
|
|
6
|
+
url: string;
|
|
7
|
+
body?: unknown;
|
|
8
|
+
}
|
|
9
|
+
interface KoaContext {
|
|
10
|
+
method: string;
|
|
11
|
+
url: string;
|
|
12
|
+
status: number;
|
|
13
|
+
request: KoaRequest;
|
|
14
|
+
body?: unknown;
|
|
15
|
+
set: (field: string, val: string) => void;
|
|
16
|
+
}
|
|
17
|
+
type KoaNext = () => Promise<void>;
|
|
18
|
+
type KoaMiddleware = (ctx: KoaContext, next: KoaNext) => Promise<void>;
|
|
19
|
+
declare function snapwyr(config?: SnapWyrConfig): KoaMiddleware;
|
|
20
|
+
|
|
21
|
+
export { snapwyr };
|
package/dist/koa.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SnapWyrConfig } from '@snapwyr/core';
|
|
2
|
+
export { LogEntry, SnapWyrConfig } from '@snapwyr/core';
|
|
3
|
+
|
|
4
|
+
interface KoaRequest {
|
|
5
|
+
method: string;
|
|
6
|
+
url: string;
|
|
7
|
+
body?: unknown;
|
|
8
|
+
}
|
|
9
|
+
interface KoaContext {
|
|
10
|
+
method: string;
|
|
11
|
+
url: string;
|
|
12
|
+
status: number;
|
|
13
|
+
request: KoaRequest;
|
|
14
|
+
body?: unknown;
|
|
15
|
+
set: (field: string, val: string) => void;
|
|
16
|
+
}
|
|
17
|
+
type KoaNext = () => Promise<void>;
|
|
18
|
+
type KoaMiddleware = (ctx: KoaContext, next: KoaNext) => Promise<void>;
|
|
19
|
+
declare function snapwyr(config?: SnapWyrConfig): KoaMiddleware;
|
|
20
|
+
|
|
21
|
+
export { snapwyr };
|
package/dist/koa.js
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/koa.ts
|
|
21
|
+
var koa_exports = {};
|
|
22
|
+
__export(koa_exports, {
|
|
23
|
+
snapwyr: () => snapwyr
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(koa_exports);
|
|
26
|
+
var import_core2 = require("@snapwyr/core");
|
|
27
|
+
|
|
28
|
+
// src/utils.ts
|
|
29
|
+
var import_core = require("@snapwyr/core");
|
|
30
|
+
function logRequest(params) {
|
|
31
|
+
const { id, method, status, duration, url, startTime, config, error } = params;
|
|
32
|
+
let { requestBody, responseBody } = params;
|
|
33
|
+
if (config.silent) return;
|
|
34
|
+
const showTimestamp = config.showTimestamp !== false;
|
|
35
|
+
const format = config.format || "pretty";
|
|
36
|
+
const slowThreshold = config.slowThreshold ?? 1e3;
|
|
37
|
+
const isSlow = duration >= slowThreshold;
|
|
38
|
+
const requestSize = requestBody ? (0, import_core.getByteSize)(requestBody) : 0;
|
|
39
|
+
const responseSize = responseBody ? (0, import_core.getByteSize)(responseBody) : 0;
|
|
40
|
+
const totalSize = requestSize + responseSize;
|
|
41
|
+
if (config.redact && config.redact.length > 0) {
|
|
42
|
+
if (requestBody)
|
|
43
|
+
requestBody = (0, import_core.redactSensitiveData)(requestBody, config.redact);
|
|
44
|
+
if (responseBody)
|
|
45
|
+
responseBody = (0, import_core.redactSensitiveData)(responseBody, config.redact);
|
|
46
|
+
}
|
|
47
|
+
const logEntry = {
|
|
48
|
+
id,
|
|
49
|
+
timestamp: new Date(startTime).toISOString(),
|
|
50
|
+
method: method.toUpperCase(),
|
|
51
|
+
url,
|
|
52
|
+
status,
|
|
53
|
+
duration,
|
|
54
|
+
slow: isSlow
|
|
55
|
+
};
|
|
56
|
+
if (config.prefix) logEntry.prefix = config.prefix;
|
|
57
|
+
if (error) logEntry.error = error;
|
|
58
|
+
if (requestBody) logEntry.requestBody = requestBody;
|
|
59
|
+
if (responseBody) logEntry.responseBody = responseBody;
|
|
60
|
+
if (config.sizeTracking) {
|
|
61
|
+
logEntry.requestSize = requestSize;
|
|
62
|
+
logEntry.responseSize = responseSize;
|
|
63
|
+
logEntry.totalSize = totalSize;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
import_core.snapwyr.emit("request", {
|
|
67
|
+
id,
|
|
68
|
+
method: method.toUpperCase(),
|
|
69
|
+
url,
|
|
70
|
+
status,
|
|
71
|
+
duration,
|
|
72
|
+
timestamp: startTime,
|
|
73
|
+
requestBody,
|
|
74
|
+
responseBody,
|
|
75
|
+
error,
|
|
76
|
+
requestSize: config.sizeTracking ? requestSize : void 0,
|
|
77
|
+
responseSize: config.sizeTracking ? responseSize : void 0,
|
|
78
|
+
direction: "incoming"
|
|
79
|
+
});
|
|
80
|
+
} catch {
|
|
81
|
+
}
|
|
82
|
+
if (config.transport) {
|
|
83
|
+
config.transport(logEntry);
|
|
84
|
+
}
|
|
85
|
+
if (format === "json") {
|
|
86
|
+
console.log(JSON.stringify(logEntry));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const useEmoji = config.emoji === true;
|
|
90
|
+
let statusEmoji = "";
|
|
91
|
+
if (useEmoji) {
|
|
92
|
+
if (error || status >= 500) statusEmoji = "\u2717 ";
|
|
93
|
+
else if (status >= 400) statusEmoji = "\u26A0 ";
|
|
94
|
+
else if (status >= 300) statusEmoji = "\u21AA ";
|
|
95
|
+
else statusEmoji = "\u2713 ";
|
|
96
|
+
}
|
|
97
|
+
const statusColor = status >= 500 ? "\x1B[31m" : status >= 400 ? "\x1B[33m" : status >= 300 ? "\x1B[36m" : "\x1B[32m";
|
|
98
|
+
const durationColor = isSlow ? "\x1B[31m" : duration < 100 ? "\x1B[32m" : "\x1B[33m";
|
|
99
|
+
const methodColors = {
|
|
100
|
+
GET: "\x1B[34m",
|
|
101
|
+
POST: "\x1B[32m",
|
|
102
|
+
PUT: "\x1B[33m",
|
|
103
|
+
PATCH: "\x1B[35m",
|
|
104
|
+
DELETE: "\x1B[31m"
|
|
105
|
+
};
|
|
106
|
+
const methodColor = methodColors[method] || "";
|
|
107
|
+
const reset = "\x1B[0m";
|
|
108
|
+
const dim = "\x1B[2m";
|
|
109
|
+
const bold = "\x1B[1m";
|
|
110
|
+
const timestamp = showTimestamp ? new Date(startTime).toISOString().slice(11, 23) + " " : "";
|
|
111
|
+
const slowIndicator = isSlow ? ` ${bold}[SLOW]${reset}` : "";
|
|
112
|
+
const requestIdDisplay = config.requestId ? `${dim}[${id}]${reset} ` : "";
|
|
113
|
+
const sizeDisplay = config.sizeTracking ? `${dim}${(0, import_core.formatBytes)(totalSize)}${reset} ` : "";
|
|
114
|
+
const parts = [
|
|
115
|
+
config.prefix ? `${dim}${config.prefix} ${reset}` : "",
|
|
116
|
+
requestIdDisplay,
|
|
117
|
+
`${dim}${timestamp}${reset}`,
|
|
118
|
+
`${methodColor}${method.padEnd(6)}${reset}`,
|
|
119
|
+
`${statusColor}${statusEmoji}${status}${reset}`,
|
|
120
|
+
`${durationColor}${duration}ms${reset}${slowIndicator}`,
|
|
121
|
+
sizeDisplay,
|
|
122
|
+
`${dim}${url}${reset}`
|
|
123
|
+
].filter(Boolean);
|
|
124
|
+
if (error) parts.push(`
|
|
125
|
+
${dim}Error: ${error}${reset}`);
|
|
126
|
+
if (requestBody) parts.push(`
|
|
127
|
+
${dim}Request: ${requestBody}${reset}`);
|
|
128
|
+
if (responseBody) parts.push(`
|
|
129
|
+
${dim}Response: ${responseBody}${reset}`);
|
|
130
|
+
console.log(parts.join(" "));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// src/koa.ts
|
|
134
|
+
function snapwyr(config = {}) {
|
|
135
|
+
return async function(ctx, next) {
|
|
136
|
+
if (config.enabled === false) {
|
|
137
|
+
await next();
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const id = (0, import_core2.generateRequestId)();
|
|
141
|
+
const startTime = Date.now();
|
|
142
|
+
if (config.requestId)
|
|
143
|
+
try {
|
|
144
|
+
ctx.set("X-Request-ID", id);
|
|
145
|
+
} catch {
|
|
146
|
+
}
|
|
147
|
+
await next();
|
|
148
|
+
const duration = Date.now() - startTime;
|
|
149
|
+
const status = ctx.status || 200;
|
|
150
|
+
if (config.statusCodes && config.statusCodes.length > 0 && !config.statusCodes.includes(status))
|
|
151
|
+
return;
|
|
152
|
+
let requestBody, responseBody;
|
|
153
|
+
if (config.logBody) {
|
|
154
|
+
try {
|
|
155
|
+
if (ctx.request.body) {
|
|
156
|
+
requestBody = typeof ctx.request.body === "string" ? ctx.request.body : JSON.stringify(ctx.request.body);
|
|
157
|
+
if (config.bodySizeLimit)
|
|
158
|
+
requestBody = requestBody.slice(0, config.bodySizeLimit);
|
|
159
|
+
}
|
|
160
|
+
if (ctx.body) {
|
|
161
|
+
responseBody = typeof ctx.body === "string" ? ctx.body : JSON.stringify(ctx.body);
|
|
162
|
+
if (config.bodySizeLimit)
|
|
163
|
+
responseBody = responseBody.slice(0, config.bodySizeLimit);
|
|
164
|
+
}
|
|
165
|
+
} catch {
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
logRequest({
|
|
169
|
+
id,
|
|
170
|
+
method: ctx.method,
|
|
171
|
+
status,
|
|
172
|
+
duration,
|
|
173
|
+
url: ctx.url,
|
|
174
|
+
startTime,
|
|
175
|
+
config,
|
|
176
|
+
requestBody: config.logBody ? requestBody : void 0,
|
|
177
|
+
responseBody: config.logBody ? responseBody : void 0
|
|
178
|
+
});
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
182
|
+
0 && (module.exports = {
|
|
183
|
+
snapwyr
|
|
184
|
+
});
|
|
185
|
+
//# sourceMappingURL=koa.js.map
|
package/dist/koa.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/koa.ts","../src/utils.ts"],"sourcesContent":["import type { SnapWyrConfig, LogEntry } from '@snapwyr/core';\nimport { generateRequestId } from '@snapwyr/core';\nimport { logRequest } from './utils.js';\n\ninterface KoaRequest {\n method: string;\n url: string;\n body?: unknown;\n}\ninterface KoaContext {\n method: string;\n url: string;\n status: number;\n request: KoaRequest;\n body?: unknown;\n set: (field: string, val: string) => void;\n}\ntype KoaNext = () => Promise<void>;\ntype KoaMiddleware = (ctx: KoaContext, next: KoaNext) => Promise<void>;\n\nexport function snapwyr(config: SnapWyrConfig = {}): KoaMiddleware {\n return async function (ctx, next) {\n if (config.enabled === false) {\n await next();\n return;\n }\n\n const id = generateRequestId();\n const startTime = Date.now();\n\n if (config.requestId)\n try {\n ctx.set('X-Request-ID', id);\n } catch {}\n\n await next();\n\n const duration = Date.now() - startTime;\n const status = ctx.status || 200;\n\n if (\n config.statusCodes &&\n config.statusCodes.length > 0 &&\n !config.statusCodes.includes(status)\n )\n return;\n\n let requestBody: string | undefined, responseBody: string | undefined;\n if (config.logBody) {\n try {\n if (ctx.request.body) {\n requestBody =\n typeof ctx.request.body === 'string'\n ? ctx.request.body\n : JSON.stringify(ctx.request.body);\n if (config.bodySizeLimit)\n requestBody = requestBody.slice(0, config.bodySizeLimit);\n }\n if (ctx.body) {\n responseBody =\n typeof ctx.body === 'string' ? ctx.body : JSON.stringify(ctx.body);\n if (config.bodySizeLimit)\n responseBody = responseBody.slice(0, config.bodySizeLimit);\n }\n } catch {}\n }\n\n logRequest({\n id,\n method: ctx.method,\n status,\n duration,\n url: ctx.url,\n startTime,\n config,\n requestBody: config.logBody ? requestBody : undefined,\n responseBody: config.logBody ? responseBody : undefined,\n });\n };\n}\n\nexport type { SnapWyrConfig, LogEntry };\n","import type { SnapWyrConfig, LogEntry } from '@snapwyr/core';\nimport {\n snapwyr as coreEmitter,\n getByteSize,\n formatBytes,\n redactSensitiveData,\n} from '@snapwyr/core';\n\nexport interface LogParams {\n id: string;\n method: string;\n status: number;\n duration: number;\n url: string;\n startTime: number;\n config: SnapWyrConfig;\n requestBody?: string;\n responseBody?: string;\n error?: string;\n}\n\nexport function logRequest(params: LogParams): void {\n const { id, method, status, duration, url, startTime, config, error } =\n params;\n let { requestBody, responseBody } = params;\n\n if (config.silent) return;\n\n const showTimestamp = config.showTimestamp !== false;\n const format = config.format || 'pretty';\n const slowThreshold = config.slowThreshold ?? 1000;\n const isSlow = duration >= slowThreshold;\n\n const requestSize = requestBody ? getByteSize(requestBody) : 0;\n const responseSize = responseBody ? getByteSize(responseBody) : 0;\n const totalSize = requestSize + responseSize;\n\n if (config.redact && config.redact.length > 0) {\n if (requestBody)\n requestBody = redactSensitiveData(requestBody, config.redact);\n if (responseBody)\n responseBody = redactSensitiveData(responseBody, config.redact);\n }\n\n const logEntry: LogEntry = {\n id,\n timestamp: new Date(startTime).toISOString(),\n method: method.toUpperCase(),\n url,\n status,\n duration,\n slow: isSlow,\n };\n\n if (config.prefix) logEntry.prefix = config.prefix;\n if (error) logEntry.error = error;\n if (requestBody) logEntry.requestBody = requestBody;\n if (responseBody) logEntry.responseBody = responseBody;\n if (config.sizeTracking) {\n logEntry.requestSize = requestSize;\n logEntry.responseSize = responseSize;\n logEntry.totalSize = totalSize;\n }\n\n try {\n coreEmitter.emit('request', {\n id,\n method: method.toUpperCase(),\n url,\n status,\n duration,\n timestamp: startTime,\n requestBody,\n responseBody,\n error,\n requestSize: config.sizeTracking ? requestSize : undefined,\n responseSize: config.sizeTracking ? responseSize : undefined,\n direction: 'incoming',\n });\n } catch {}\n\n if (config.transport) {\n config.transport(logEntry);\n }\n\n if (format === 'json') {\n console.log(JSON.stringify(logEntry));\n return;\n }\n\n const useEmoji = config.emoji === true;\n let statusEmoji = '';\n if (useEmoji) {\n if (error || status >= 500) statusEmoji = '✗ ';\n else if (status >= 400) statusEmoji = '⚠ ';\n else if (status >= 300) statusEmoji = '↪ ';\n else statusEmoji = '✓ ';\n }\n\n const statusColor =\n status >= 500\n ? '\\x1b[31m'\n : status >= 400\n ? '\\x1b[33m'\n : status >= 300\n ? '\\x1b[36m'\n : '\\x1b[32m';\n const durationColor = isSlow\n ? '\\x1b[31m'\n : duration < 100\n ? '\\x1b[32m'\n : '\\x1b[33m';\n const methodColors: Record<string, string> = {\n GET: '\\x1b[34m',\n POST: '\\x1b[32m',\n PUT: '\\x1b[33m',\n PATCH: '\\x1b[35m',\n DELETE: '\\x1b[31m',\n };\n const methodColor = methodColors[method] || '';\n const reset = '\\x1b[0m';\n const dim = '\\x1b[2m';\n const bold = '\\x1b[1m';\n const timestamp = showTimestamp\n ? new Date(startTime).toISOString().slice(11, 23) + ' '\n : '';\n const slowIndicator = isSlow ? ` ${bold}[SLOW]${reset}` : '';\n const requestIdDisplay = config.requestId ? `${dim}[${id}]${reset} ` : '';\n const sizeDisplay = config.sizeTracking\n ? `${dim}${formatBytes(totalSize)}${reset} `\n : '';\n\n const parts = [\n config.prefix ? `${dim}${config.prefix} ${reset}` : '',\n requestIdDisplay,\n `${dim}${timestamp}${reset}`,\n `${methodColor}${method.padEnd(6)}${reset}`,\n `${statusColor}${statusEmoji}${status}${reset}`,\n `${durationColor}${duration}ms${reset}${slowIndicator}`,\n sizeDisplay,\n `${dim}${url}${reset}`,\n ].filter(Boolean);\n\n if (error) parts.push(`\\n ${dim}Error: ${error}${reset}`);\n if (requestBody) parts.push(`\\n ${dim}Request: ${requestBody}${reset}`);\n if (responseBody) parts.push(`\\n ${dim}Response: ${responseBody}${reset}`);\n\n console.log(parts.join(' '));\n}\n"],"mappings":"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","names":["import_core","coreEmitter"]}
|
package/dist/koa.mjs
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// src/koa.ts
|
|
2
|
+
import { generateRequestId } from "@snapwyr/core";
|
|
3
|
+
|
|
4
|
+
// src/utils.ts
|
|
5
|
+
import {
|
|
6
|
+
snapwyr as coreEmitter,
|
|
7
|
+
getByteSize,
|
|
8
|
+
formatBytes,
|
|
9
|
+
redactSensitiveData
|
|
10
|
+
} from "@snapwyr/core";
|
|
11
|
+
function logRequest(params) {
|
|
12
|
+
const { id, method, status, duration, url, startTime, config, error } = params;
|
|
13
|
+
let { requestBody, responseBody } = params;
|
|
14
|
+
if (config.silent) return;
|
|
15
|
+
const showTimestamp = config.showTimestamp !== false;
|
|
16
|
+
const format = config.format || "pretty";
|
|
17
|
+
const slowThreshold = config.slowThreshold ?? 1e3;
|
|
18
|
+
const isSlow = duration >= slowThreshold;
|
|
19
|
+
const requestSize = requestBody ? getByteSize(requestBody) : 0;
|
|
20
|
+
const responseSize = responseBody ? getByteSize(responseBody) : 0;
|
|
21
|
+
const totalSize = requestSize + responseSize;
|
|
22
|
+
if (config.redact && config.redact.length > 0) {
|
|
23
|
+
if (requestBody)
|
|
24
|
+
requestBody = redactSensitiveData(requestBody, config.redact);
|
|
25
|
+
if (responseBody)
|
|
26
|
+
responseBody = redactSensitiveData(responseBody, config.redact);
|
|
27
|
+
}
|
|
28
|
+
const logEntry = {
|
|
29
|
+
id,
|
|
30
|
+
timestamp: new Date(startTime).toISOString(),
|
|
31
|
+
method: method.toUpperCase(),
|
|
32
|
+
url,
|
|
33
|
+
status,
|
|
34
|
+
duration,
|
|
35
|
+
slow: isSlow
|
|
36
|
+
};
|
|
37
|
+
if (config.prefix) logEntry.prefix = config.prefix;
|
|
38
|
+
if (error) logEntry.error = error;
|
|
39
|
+
if (requestBody) logEntry.requestBody = requestBody;
|
|
40
|
+
if (responseBody) logEntry.responseBody = responseBody;
|
|
41
|
+
if (config.sizeTracking) {
|
|
42
|
+
logEntry.requestSize = requestSize;
|
|
43
|
+
logEntry.responseSize = responseSize;
|
|
44
|
+
logEntry.totalSize = totalSize;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
coreEmitter.emit("request", {
|
|
48
|
+
id,
|
|
49
|
+
method: method.toUpperCase(),
|
|
50
|
+
url,
|
|
51
|
+
status,
|
|
52
|
+
duration,
|
|
53
|
+
timestamp: startTime,
|
|
54
|
+
requestBody,
|
|
55
|
+
responseBody,
|
|
56
|
+
error,
|
|
57
|
+
requestSize: config.sizeTracking ? requestSize : void 0,
|
|
58
|
+
responseSize: config.sizeTracking ? responseSize : void 0,
|
|
59
|
+
direction: "incoming"
|
|
60
|
+
});
|
|
61
|
+
} catch {
|
|
62
|
+
}
|
|
63
|
+
if (config.transport) {
|
|
64
|
+
config.transport(logEntry);
|
|
65
|
+
}
|
|
66
|
+
if (format === "json") {
|
|
67
|
+
console.log(JSON.stringify(logEntry));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const useEmoji = config.emoji === true;
|
|
71
|
+
let statusEmoji = "";
|
|
72
|
+
if (useEmoji) {
|
|
73
|
+
if (error || status >= 500) statusEmoji = "\u2717 ";
|
|
74
|
+
else if (status >= 400) statusEmoji = "\u26A0 ";
|
|
75
|
+
else if (status >= 300) statusEmoji = "\u21AA ";
|
|
76
|
+
else statusEmoji = "\u2713 ";
|
|
77
|
+
}
|
|
78
|
+
const statusColor = status >= 500 ? "\x1B[31m" : status >= 400 ? "\x1B[33m" : status >= 300 ? "\x1B[36m" : "\x1B[32m";
|
|
79
|
+
const durationColor = isSlow ? "\x1B[31m" : duration < 100 ? "\x1B[32m" : "\x1B[33m";
|
|
80
|
+
const methodColors = {
|
|
81
|
+
GET: "\x1B[34m",
|
|
82
|
+
POST: "\x1B[32m",
|
|
83
|
+
PUT: "\x1B[33m",
|
|
84
|
+
PATCH: "\x1B[35m",
|
|
85
|
+
DELETE: "\x1B[31m"
|
|
86
|
+
};
|
|
87
|
+
const methodColor = methodColors[method] || "";
|
|
88
|
+
const reset = "\x1B[0m";
|
|
89
|
+
const dim = "\x1B[2m";
|
|
90
|
+
const bold = "\x1B[1m";
|
|
91
|
+
const timestamp = showTimestamp ? new Date(startTime).toISOString().slice(11, 23) + " " : "";
|
|
92
|
+
const slowIndicator = isSlow ? ` ${bold}[SLOW]${reset}` : "";
|
|
93
|
+
const requestIdDisplay = config.requestId ? `${dim}[${id}]${reset} ` : "";
|
|
94
|
+
const sizeDisplay = config.sizeTracking ? `${dim}${formatBytes(totalSize)}${reset} ` : "";
|
|
95
|
+
const parts = [
|
|
96
|
+
config.prefix ? `${dim}${config.prefix} ${reset}` : "",
|
|
97
|
+
requestIdDisplay,
|
|
98
|
+
`${dim}${timestamp}${reset}`,
|
|
99
|
+
`${methodColor}${method.padEnd(6)}${reset}`,
|
|
100
|
+
`${statusColor}${statusEmoji}${status}${reset}`,
|
|
101
|
+
`${durationColor}${duration}ms${reset}${slowIndicator}`,
|
|
102
|
+
sizeDisplay,
|
|
103
|
+
`${dim}${url}${reset}`
|
|
104
|
+
].filter(Boolean);
|
|
105
|
+
if (error) parts.push(`
|
|
106
|
+
${dim}Error: ${error}${reset}`);
|
|
107
|
+
if (requestBody) parts.push(`
|
|
108
|
+
${dim}Request: ${requestBody}${reset}`);
|
|
109
|
+
if (responseBody) parts.push(`
|
|
110
|
+
${dim}Response: ${responseBody}${reset}`);
|
|
111
|
+
console.log(parts.join(" "));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// src/koa.ts
|
|
115
|
+
function snapwyr(config = {}) {
|
|
116
|
+
return async function(ctx, next) {
|
|
117
|
+
if (config.enabled === false) {
|
|
118
|
+
await next();
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const id = generateRequestId();
|
|
122
|
+
const startTime = Date.now();
|
|
123
|
+
if (config.requestId)
|
|
124
|
+
try {
|
|
125
|
+
ctx.set("X-Request-ID", id);
|
|
126
|
+
} catch {
|
|
127
|
+
}
|
|
128
|
+
await next();
|
|
129
|
+
const duration = Date.now() - startTime;
|
|
130
|
+
const status = ctx.status || 200;
|
|
131
|
+
if (config.statusCodes && config.statusCodes.length > 0 && !config.statusCodes.includes(status))
|
|
132
|
+
return;
|
|
133
|
+
let requestBody, responseBody;
|
|
134
|
+
if (config.logBody) {
|
|
135
|
+
try {
|
|
136
|
+
if (ctx.request.body) {
|
|
137
|
+
requestBody = typeof ctx.request.body === "string" ? ctx.request.body : JSON.stringify(ctx.request.body);
|
|
138
|
+
if (config.bodySizeLimit)
|
|
139
|
+
requestBody = requestBody.slice(0, config.bodySizeLimit);
|
|
140
|
+
}
|
|
141
|
+
if (ctx.body) {
|
|
142
|
+
responseBody = typeof ctx.body === "string" ? ctx.body : JSON.stringify(ctx.body);
|
|
143
|
+
if (config.bodySizeLimit)
|
|
144
|
+
responseBody = responseBody.slice(0, config.bodySizeLimit);
|
|
145
|
+
}
|
|
146
|
+
} catch {
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
logRequest({
|
|
150
|
+
id,
|
|
151
|
+
method: ctx.method,
|
|
152
|
+
status,
|
|
153
|
+
duration,
|
|
154
|
+
url: ctx.url,
|
|
155
|
+
startTime,
|
|
156
|
+
config,
|
|
157
|
+
requestBody: config.logBody ? requestBody : void 0,
|
|
158
|
+
responseBody: config.logBody ? responseBody : void 0
|
|
159
|
+
});
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
export {
|
|
163
|
+
snapwyr
|
|
164
|
+
};
|
|
165
|
+
//# sourceMappingURL=koa.mjs.map
|