request-scope-api 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 +275 -0
- package/dist/cjs/adapters/adapter.interface.js +9 -0
- package/dist/cjs/adapters/adapter.interface.js.map +1 -0
- package/dist/cjs/adapters/mongo.adapter.js +188 -0
- package/dist/cjs/adapters/mongo.adapter.js.map +1 -0
- package/dist/cjs/adapters/mysql.adapter.js +243 -0
- package/dist/cjs/adapters/mysql.adapter.js.map +1 -0
- package/dist/cjs/adapters/pg.adapter.js +334 -0
- package/dist/cjs/adapters/pg.adapter.js.map +1 -0
- package/dist/cjs/capture.js +310 -0
- package/dist/cjs/capture.js.map +1 -0
- package/dist/cjs/config.js +122 -0
- package/dist/cjs/config.js.map +1 -0
- package/dist/cjs/dashboard/api.js +173 -0
- package/dist/cjs/dashboard/api.js.map +1 -0
- package/dist/cjs/dashboard/router.js +96 -0
- package/dist/cjs/dashboard/router.js.map +1 -0
- package/dist/cjs/index.js +49 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/masker.js +73 -0
- package/dist/cjs/masker.js.map +1 -0
- package/dist/cjs/middleware.js +198 -0
- package/dist/cjs/middleware.js.map +1 -0
- package/dist/cjs/queue.js +114 -0
- package/dist/cjs/queue.js.map +1 -0
- package/dist/cjs/retention.js +64 -0
- package/dist/cjs/retention.js.map +1 -0
- package/dist/cjs/types.js +9 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/dashboard/assets/index-C0TqFHk6.css +1 -0
- package/dist/dashboard/assets/index-MCuAZo4Q.js +67 -0
- package/dist/dashboard/index.html +13 -0
- package/dist/esm/adapters/adapter.interface.js +8 -0
- package/dist/esm/adapters/adapter.interface.js.map +1 -0
- package/dist/esm/adapters/mongo.adapter.js +184 -0
- package/dist/esm/adapters/mongo.adapter.js.map +1 -0
- package/dist/esm/adapters/mysql.adapter.js +236 -0
- package/dist/esm/adapters/mysql.adapter.js.map +1 -0
- package/dist/esm/adapters/pg.adapter.js +330 -0
- package/dist/esm/adapters/pg.adapter.js.map +1 -0
- package/dist/esm/capture.js +304 -0
- package/dist/esm/capture.js.map +1 -0
- package/dist/esm/config.js +117 -0
- package/dist/esm/config.js.map +1 -0
- package/dist/esm/dashboard/api.js +168 -0
- package/dist/esm/dashboard/api.js.map +1 -0
- package/dist/esm/dashboard/router.js +90 -0
- package/dist/esm/dashboard/router.js.map +1 -0
- package/dist/esm/index.js +50 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/masker.js +70 -0
- package/dist/esm/masker.js.map +1 -0
- package/dist/esm/middleware.js +193 -0
- package/dist/esm/middleware.js.map +1 -0
- package/dist/esm/queue.js +110 -0
- package/dist/esm/queue.js.map +1 -0
- package/dist/esm/retention.js +60 -0
- package/dist/esm/retention.js.map +1 -0
- package/dist/esm/types.js +8 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/types/adapters/adapter.interface.d.ts +7 -0
- package/dist/types/adapters/mongo.adapter.d.ts +25 -0
- package/dist/types/adapters/mysql.adapter.d.ts +24 -0
- package/dist/types/adapters/pg.adapter.d.ts +29 -0
- package/dist/types/capture.d.ts +88 -0
- package/dist/types/config.d.ts +38 -0
- package/dist/types/dashboard/api.d.ts +49 -0
- package/dist/types/dashboard/router.d.ts +28 -0
- package/dist/types/index.d.ts +31 -0
- package/dist/types/masker.d.ts +15 -0
- package/dist/types/middleware.d.ts +67 -0
- package/dist/types/queue.d.ts +49 -0
- package/dist/types/retention.d.ts +30 -0
- package/dist/types/types.d.ts +101 -0
- package/package.json +48 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MySQLAdapter — StorageAdapter implementation for MySQL using mysql2/promise.
|
|
4
|
+
*
|
|
5
|
+
* Compiles under `strict: true` with zero errors.
|
|
6
|
+
* Requirements: 1.6, 1.7, 6.1, 6.3, 6.5, 7.4
|
|
7
|
+
*/
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.MySQLAdapter = void 0;
|
|
13
|
+
const promise_1 = __importDefault(require("mysql2/promise"));
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Column name mapping: JS camelCase → SQL snake_case
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
const SORT_COLUMN_MAP = {
|
|
18
|
+
timestamp: 'timestamp',
|
|
19
|
+
responseTime: 'response_time',
|
|
20
|
+
statusCode: 'status_code',
|
|
21
|
+
};
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// DDL
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
const DDL = `
|
|
26
|
+
CREATE TABLE IF NOT EXISTS requestscope_records (
|
|
27
|
+
id VARCHAR(36) NOT NULL PRIMARY KEY,
|
|
28
|
+
method VARCHAR(10) NOT NULL,
|
|
29
|
+
url TEXT NOT NULL,
|
|
30
|
+
route VARCHAR(500) NULL,
|
|
31
|
+
query_params JSON NOT NULL,
|
|
32
|
+
path_params JSON NOT NULL,
|
|
33
|
+
request_headers JSON NOT NULL,
|
|
34
|
+
request_body MEDIUMTEXT NOT NULL,
|
|
35
|
+
request_body_size INT UNSIGNED NOT NULL,
|
|
36
|
+
client_ip VARCHAR(45) NOT NULL,
|
|
37
|
+
user_agent TEXT NOT NULL,
|
|
38
|
+
status_code SMALLINT NOT NULL,
|
|
39
|
+
response_headers JSON NOT NULL,
|
|
40
|
+
response_body MEDIUMTEXT NOT NULL,
|
|
41
|
+
response_body_size INT UNSIGNED NOT NULL,
|
|
42
|
+
response_time FLOAT NOT NULL,
|
|
43
|
+
error_message TEXT NULL,
|
|
44
|
+
error_stack TEXT NULL,
|
|
45
|
+
error_status_code SMALLINT NULL,
|
|
46
|
+
timestamp VARCHAR(30) NOT NULL,
|
|
47
|
+
INDEX idx_timestamp (timestamp),
|
|
48
|
+
INDEX idx_status_code (status_code),
|
|
49
|
+
INDEX idx_method (method)
|
|
50
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
51
|
+
`.trim();
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Helpers
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
/**
|
|
56
|
+
* Parse a JSON column value. MySQL drivers may return it as a string or
|
|
57
|
+
* as an already-parsed object depending on the version/config.
|
|
58
|
+
*/
|
|
59
|
+
function parseJson(value) {
|
|
60
|
+
if (value === null || value === undefined)
|
|
61
|
+
return {};
|
|
62
|
+
if (typeof value === 'object')
|
|
63
|
+
return value;
|
|
64
|
+
if (typeof value === 'string') {
|
|
65
|
+
try {
|
|
66
|
+
return JSON.parse(value);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return {};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return {};
|
|
73
|
+
}
|
|
74
|
+
/** Map a database row back to a `RequestRecord`. */
|
|
75
|
+
function rowToRecord(row) {
|
|
76
|
+
return {
|
|
77
|
+
id: row.id,
|
|
78
|
+
method: row.method,
|
|
79
|
+
url: row.url,
|
|
80
|
+
route: row.route,
|
|
81
|
+
queryParams: parseJson(row.query_params),
|
|
82
|
+
pathParams: parseJson(row.path_params),
|
|
83
|
+
requestHeaders: parseJson(row.request_headers),
|
|
84
|
+
requestBody: row.request_body,
|
|
85
|
+
requestBodySize: row.request_body_size,
|
|
86
|
+
clientIp: row.client_ip,
|
|
87
|
+
userAgent: row.user_agent,
|
|
88
|
+
statusCode: row.status_code,
|
|
89
|
+
responseHeaders: parseJson(row.response_headers),
|
|
90
|
+
responseBody: row.response_body,
|
|
91
|
+
responseBodySize: row.response_body_size,
|
|
92
|
+
responseTime: row.response_time,
|
|
93
|
+
errorMessage: row.error_message,
|
|
94
|
+
errorStack: row.error_stack,
|
|
95
|
+
errorStatusCode: row.error_status_code,
|
|
96
|
+
timestamp: row.timestamp,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/** Resolve the `statusCodeGroup` filter to a `[min, max)` pair. */
|
|
100
|
+
function statusGroupRange(group) {
|
|
101
|
+
const base = parseInt(group[0], 10) * 100;
|
|
102
|
+
return [base, base + 100];
|
|
103
|
+
}
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// MySQLAdapter
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
class MySQLAdapter {
|
|
108
|
+
constructor(config) {
|
|
109
|
+
this.pool = null;
|
|
110
|
+
this.config = config;
|
|
111
|
+
}
|
|
112
|
+
// -------------------------------------------------------------------------
|
|
113
|
+
// initialize
|
|
114
|
+
// -------------------------------------------------------------------------
|
|
115
|
+
async initialize() {
|
|
116
|
+
const options = {
|
|
117
|
+
host: this.config.host ?? 'localhost',
|
|
118
|
+
port: this.config.port ?? 3306,
|
|
119
|
+
database: this.config.database,
|
|
120
|
+
user: this.config.username,
|
|
121
|
+
password: this.config.password,
|
|
122
|
+
connectionLimit: this.config.poolSize ?? 5,
|
|
123
|
+
ssl: this.config.ssl ? { rejectUnauthorized: true } : undefined,
|
|
124
|
+
// Return JSON columns as strings so we control the parsing
|
|
125
|
+
typeCast: false,
|
|
126
|
+
};
|
|
127
|
+
this.pool = promise_1.default.createPool(options);
|
|
128
|
+
await this.pool.execute(DDL);
|
|
129
|
+
}
|
|
130
|
+
// -------------------------------------------------------------------------
|
|
131
|
+
// insert
|
|
132
|
+
// -------------------------------------------------------------------------
|
|
133
|
+
async insert(records) {
|
|
134
|
+
if (records.length === 0)
|
|
135
|
+
return;
|
|
136
|
+
const pool = this.getPool();
|
|
137
|
+
// Build: INSERT INTO ... VALUES (?, ...), (?, ...), ...
|
|
138
|
+
const columnList = [
|
|
139
|
+
'id', 'method', 'url', 'route',
|
|
140
|
+
'query_params', 'path_params', 'request_headers',
|
|
141
|
+
'request_body', 'request_body_size',
|
|
142
|
+
'client_ip', 'user_agent',
|
|
143
|
+
'status_code', 'response_headers',
|
|
144
|
+
'response_body', 'response_body_size',
|
|
145
|
+
'response_time',
|
|
146
|
+
'error_message', 'error_stack', 'error_status_code',
|
|
147
|
+
'timestamp',
|
|
148
|
+
];
|
|
149
|
+
const placeholderRow = `(${columnList.map(() => '?').join(', ')})`;
|
|
150
|
+
const placeholders = records.map(() => placeholderRow).join(', ');
|
|
151
|
+
const sql = `INSERT INTO requestscope_records (${columnList.join(', ')}) VALUES ${placeholders}`;
|
|
152
|
+
const values = [];
|
|
153
|
+
for (const r of records) {
|
|
154
|
+
values.push(r.id, r.method, r.url, r.route, JSON.stringify(r.queryParams), JSON.stringify(r.pathParams), JSON.stringify(r.requestHeaders), r.requestBody, r.requestBodySize, r.clientIp, r.userAgent, r.statusCode, JSON.stringify(r.responseHeaders), r.responseBody, r.responseBodySize, r.responseTime, r.errorMessage, r.errorStack, r.errorStatusCode, r.timestamp);
|
|
155
|
+
}
|
|
156
|
+
await pool.execute(sql, values);
|
|
157
|
+
}
|
|
158
|
+
// -------------------------------------------------------------------------
|
|
159
|
+
// query
|
|
160
|
+
// -------------------------------------------------------------------------
|
|
161
|
+
async query(filters, pagination) {
|
|
162
|
+
const pool = this.getPool();
|
|
163
|
+
const conditions = [];
|
|
164
|
+
const params = [];
|
|
165
|
+
// id — exact match
|
|
166
|
+
if (filters.id !== undefined) {
|
|
167
|
+
conditions.push('id = ?');
|
|
168
|
+
params.push(filters.id);
|
|
169
|
+
}
|
|
170
|
+
// search — url LIKE ?
|
|
171
|
+
if (filters.search !== undefined) {
|
|
172
|
+
conditions.push('url LIKE ?');
|
|
173
|
+
params.push(`%${filters.search}%`);
|
|
174
|
+
}
|
|
175
|
+
// startDate — timestamp >= ?
|
|
176
|
+
if (filters.startDate !== undefined) {
|
|
177
|
+
conditions.push('timestamp >= ?');
|
|
178
|
+
params.push(filters.startDate);
|
|
179
|
+
}
|
|
180
|
+
// endDate — timestamp <= ?
|
|
181
|
+
if (filters.endDate !== undefined) {
|
|
182
|
+
conditions.push('timestamp <= ?');
|
|
183
|
+
params.push(filters.endDate);
|
|
184
|
+
}
|
|
185
|
+
// statusCode (exact, takes precedence over group)
|
|
186
|
+
if (filters.statusCode !== undefined) {
|
|
187
|
+
conditions.push('status_code = ?');
|
|
188
|
+
params.push(filters.statusCode);
|
|
189
|
+
}
|
|
190
|
+
else if (filters.statusCodeGroup !== undefined) {
|
|
191
|
+
const [min, max] = statusGroupRange(filters.statusCodeGroup);
|
|
192
|
+
conditions.push('status_code >= ? AND status_code < ?');
|
|
193
|
+
params.push(min, max);
|
|
194
|
+
}
|
|
195
|
+
// method — case-insensitive
|
|
196
|
+
if (filters.method !== undefined) {
|
|
197
|
+
conditions.push('LOWER(method) = LOWER(?)');
|
|
198
|
+
params.push(filters.method);
|
|
199
|
+
}
|
|
200
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
201
|
+
// Sort
|
|
202
|
+
const sortColRaw = filters.sortBy ?? 'timestamp';
|
|
203
|
+
const sortCol = SORT_COLUMN_MAP[sortColRaw] ?? 'timestamp';
|
|
204
|
+
const sortDir = (filters.sortOrder ?? 'desc').toUpperCase() === 'ASC' ? 'ASC' : 'DESC';
|
|
205
|
+
const orderClause = `ORDER BY ${sortCol} ${sortDir}`;
|
|
206
|
+
// COUNT query (reuses same params)
|
|
207
|
+
const countSql = `SELECT COUNT(*) AS total FROM requestscope_records ${whereClause}`;
|
|
208
|
+
const [countRows] = await pool.execute(countSql, params);
|
|
209
|
+
const total = Number(countRows[0]?.total ?? 0);
|
|
210
|
+
// Page slice
|
|
211
|
+
const { page, pageSize } = pagination;
|
|
212
|
+
const offset = (Math.max(1, page) - 1) * pageSize;
|
|
213
|
+
const dataSql = `
|
|
214
|
+
SELECT * FROM requestscope_records
|
|
215
|
+
${whereClause}
|
|
216
|
+
${orderClause}
|
|
217
|
+
LIMIT ? OFFSET ?
|
|
218
|
+
`.trim();
|
|
219
|
+
const [rows] = await pool.execute(dataSql, [...params, pageSize, offset]);
|
|
220
|
+
const records = rows.map(rowToRecord);
|
|
221
|
+
return { records, total };
|
|
222
|
+
}
|
|
223
|
+
// -------------------------------------------------------------------------
|
|
224
|
+
// deleteOlderThan
|
|
225
|
+
// -------------------------------------------------------------------------
|
|
226
|
+
async deleteOlderThan(date) {
|
|
227
|
+
const pool = this.getPool();
|
|
228
|
+
const iso = date.toISOString();
|
|
229
|
+
const [result] = await pool.execute('DELETE FROM requestscope_records WHERE timestamp < ?', [iso]);
|
|
230
|
+
return result.affectedRows;
|
|
231
|
+
}
|
|
232
|
+
// -------------------------------------------------------------------------
|
|
233
|
+
// Private helpers
|
|
234
|
+
// -------------------------------------------------------------------------
|
|
235
|
+
getPool() {
|
|
236
|
+
if (this.pool === null) {
|
|
237
|
+
throw new Error('MySQLAdapter: call initialize() before using the adapter');
|
|
238
|
+
}
|
|
239
|
+
return this.pool;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
exports.MySQLAdapter = MySQLAdapter;
|
|
243
|
+
//# sourceMappingURL=mysql.adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mysql.adapter.js","sourceRoot":"","sources":["../../../src/adapters/mysql.adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* PgAdapter — StorageAdapter implementation for PostgreSQL using pg.
|
|
4
|
+
*
|
|
5
|
+
* Compiles under `strict: true` with zero errors.
|
|
6
|
+
* Requirements: 1.6, 1.7, 6.1, 6.4, 6.5, 7.4
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.PgAdapter = void 0;
|
|
10
|
+
const pg_1 = require("pg");
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Column name mapping: JS camelCase → SQL snake_case
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
const SORT_COLUMN_MAP = {
|
|
15
|
+
timestamp: 'timestamp',
|
|
16
|
+
responseTime: 'response_time',
|
|
17
|
+
statusCode: 'status_code',
|
|
18
|
+
};
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// DDL
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
const DDL_TABLE = `
|
|
23
|
+
CREATE TABLE IF NOT EXISTS requestscope_records (
|
|
24
|
+
id VARCHAR(36) NOT NULL PRIMARY KEY,
|
|
25
|
+
method VARCHAR(10) NOT NULL,
|
|
26
|
+
url TEXT NOT NULL,
|
|
27
|
+
route TEXT,
|
|
28
|
+
query_params JSONB NOT NULL,
|
|
29
|
+
path_params JSONB NOT NULL,
|
|
30
|
+
request_headers JSONB NOT NULL,
|
|
31
|
+
request_body TEXT NOT NULL,
|
|
32
|
+
request_body_size INTEGER NOT NULL,
|
|
33
|
+
client_ip VARCHAR(45) NOT NULL,
|
|
34
|
+
user_agent TEXT NOT NULL,
|
|
35
|
+
status_code SMALLINT NOT NULL,
|
|
36
|
+
response_headers JSONB NOT NULL,
|
|
37
|
+
response_body TEXT NOT NULL,
|
|
38
|
+
response_body_size INTEGER NOT NULL,
|
|
39
|
+
response_time REAL NOT NULL,
|
|
40
|
+
error_message TEXT,
|
|
41
|
+
error_stack TEXT,
|
|
42
|
+
error_status_code SMALLINT,
|
|
43
|
+
timestamp VARCHAR(30) NOT NULL
|
|
44
|
+
)
|
|
45
|
+
`.trim();
|
|
46
|
+
const DDL_IDX_TIMESTAMP = `CREATE INDEX IF NOT EXISTS idx_rs_timestamp ON requestscope_records (timestamp DESC)`;
|
|
47
|
+
const DDL_IDX_STATUS = `CREATE INDEX IF NOT EXISTS idx_rs_status ON requestscope_records (status_code)`;
|
|
48
|
+
const DDL_IDX_METHOD = `CREATE INDEX IF NOT EXISTS idx_rs_method ON requestscope_records (method)`;
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// Helpers
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
/**
|
|
53
|
+
* Ensure a JSONB column value (which pg already parses to an object) is
|
|
54
|
+
* returned as `Record<string, string>`. Falls back to `{}` on any error.
|
|
55
|
+
*/
|
|
56
|
+
function parseJsonb(value) {
|
|
57
|
+
if (value === null || value === undefined)
|
|
58
|
+
return {};
|
|
59
|
+
if (typeof value === 'object')
|
|
60
|
+
return value;
|
|
61
|
+
if (typeof value === 'string') {
|
|
62
|
+
try {
|
|
63
|
+
return JSON.parse(value);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return {};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return {};
|
|
70
|
+
}
|
|
71
|
+
/** Map a database row back to a `RequestRecord`. */
|
|
72
|
+
function rowToRecord(row) {
|
|
73
|
+
return {
|
|
74
|
+
id: row.id,
|
|
75
|
+
method: row.method,
|
|
76
|
+
url: row.url,
|
|
77
|
+
route: row.route,
|
|
78
|
+
queryParams: parseJsonb(row.query_params),
|
|
79
|
+
pathParams: parseJsonb(row.path_params),
|
|
80
|
+
requestHeaders: parseJsonb(row.request_headers),
|
|
81
|
+
requestBody: row.request_body,
|
|
82
|
+
requestBodySize: Number(row.request_body_size),
|
|
83
|
+
clientIp: row.client_ip,
|
|
84
|
+
userAgent: row.user_agent,
|
|
85
|
+
statusCode: Number(row.status_code),
|
|
86
|
+
responseHeaders: parseJsonb(row.response_headers),
|
|
87
|
+
responseBody: row.response_body,
|
|
88
|
+
responseBodySize: Number(row.response_body_size),
|
|
89
|
+
responseTime: Number(row.response_time),
|
|
90
|
+
errorMessage: row.error_message,
|
|
91
|
+
errorStack: row.error_stack,
|
|
92
|
+
errorStatusCode: row.error_status_code !== null ? Number(row.error_status_code) : null,
|
|
93
|
+
timestamp: row.timestamp,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/** Resolve the `statusCodeGroup` filter to a `[min, max)` pair. */
|
|
97
|
+
function statusGroupRange(group) {
|
|
98
|
+
const base = parseInt(group[0], 10) * 100;
|
|
99
|
+
return [base, base + 100];
|
|
100
|
+
}
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
// PgAdapter
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
class PgAdapter {
|
|
105
|
+
constructor(config) {
|
|
106
|
+
this.pool = null;
|
|
107
|
+
this.config = config;
|
|
108
|
+
}
|
|
109
|
+
// -------------------------------------------------------------------------
|
|
110
|
+
// initialize
|
|
111
|
+
// -------------------------------------------------------------------------
|
|
112
|
+
async initialize() {
|
|
113
|
+
const poolConfig = {
|
|
114
|
+
host: this.config.host ?? 'localhost',
|
|
115
|
+
port: this.config.port ?? 5432,
|
|
116
|
+
database: this.config.database,
|
|
117
|
+
user: this.config.username,
|
|
118
|
+
password: this.config.password,
|
|
119
|
+
max: this.config.poolSize ?? 5,
|
|
120
|
+
ssl: this.config.ssl ? { rejectUnauthorized: true } : undefined,
|
|
121
|
+
};
|
|
122
|
+
this.pool = new pg_1.Pool(poolConfig);
|
|
123
|
+
const client = await this.pool.connect();
|
|
124
|
+
try {
|
|
125
|
+
await client.query(DDL_TABLE);
|
|
126
|
+
await client.query(DDL_IDX_TIMESTAMP);
|
|
127
|
+
await client.query(DDL_IDX_STATUS);
|
|
128
|
+
await client.query(DDL_IDX_METHOD);
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
client.release();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// -------------------------------------------------------------------------
|
|
135
|
+
// insert
|
|
136
|
+
// -------------------------------------------------------------------------
|
|
137
|
+
/**
|
|
138
|
+
* Batch-inserts records using unnest arrays for efficient multi-row inserts.
|
|
139
|
+
*
|
|
140
|
+
* INSERT INTO requestscope_records (col1, col2, ...)
|
|
141
|
+
* SELECT * FROM unnest($1::varchar[], $2::text[], ...)
|
|
142
|
+
*/
|
|
143
|
+
async insert(records) {
|
|
144
|
+
if (records.length === 0)
|
|
145
|
+
return;
|
|
146
|
+
const pool = this.getPool();
|
|
147
|
+
// Collect per-column arrays
|
|
148
|
+
const ids = [];
|
|
149
|
+
const methods = [];
|
|
150
|
+
const urls = [];
|
|
151
|
+
const routes = [];
|
|
152
|
+
const queryParams = [];
|
|
153
|
+
const pathParams = [];
|
|
154
|
+
const requestHeaders = [];
|
|
155
|
+
const requestBodies = [];
|
|
156
|
+
const requestBodySizes = [];
|
|
157
|
+
const clientIps = [];
|
|
158
|
+
const userAgents = [];
|
|
159
|
+
const statusCodes = [];
|
|
160
|
+
const responseHeaders = [];
|
|
161
|
+
const responseBodies = [];
|
|
162
|
+
const responseBodySizes = [];
|
|
163
|
+
const responseTimes = [];
|
|
164
|
+
const errorMessages = [];
|
|
165
|
+
const errorStacks = [];
|
|
166
|
+
const errorStatusCodes = [];
|
|
167
|
+
const timestamps = [];
|
|
168
|
+
for (const r of records) {
|
|
169
|
+
ids.push(r.id);
|
|
170
|
+
methods.push(r.method);
|
|
171
|
+
urls.push(r.url);
|
|
172
|
+
routes.push(r.route);
|
|
173
|
+
queryParams.push(JSON.stringify(r.queryParams));
|
|
174
|
+
pathParams.push(JSON.stringify(r.pathParams));
|
|
175
|
+
requestHeaders.push(JSON.stringify(r.requestHeaders));
|
|
176
|
+
requestBodies.push(r.requestBody);
|
|
177
|
+
requestBodySizes.push(r.requestBodySize);
|
|
178
|
+
clientIps.push(r.clientIp);
|
|
179
|
+
userAgents.push(r.userAgent);
|
|
180
|
+
statusCodes.push(r.statusCode);
|
|
181
|
+
responseHeaders.push(JSON.stringify(r.responseHeaders));
|
|
182
|
+
responseBodies.push(r.responseBody);
|
|
183
|
+
responseBodySizes.push(r.responseBodySize);
|
|
184
|
+
responseTimes.push(r.responseTime);
|
|
185
|
+
errorMessages.push(r.errorMessage);
|
|
186
|
+
errorStacks.push(r.errorStack);
|
|
187
|
+
errorStatusCodes.push(r.errorStatusCode);
|
|
188
|
+
timestamps.push(r.timestamp);
|
|
189
|
+
}
|
|
190
|
+
const sql = `
|
|
191
|
+
INSERT INTO requestscope_records (
|
|
192
|
+
id, method, url, route,
|
|
193
|
+
query_params, path_params, request_headers,
|
|
194
|
+
request_body, request_body_size,
|
|
195
|
+
client_ip, user_agent,
|
|
196
|
+
status_code, response_headers,
|
|
197
|
+
response_body, response_body_size,
|
|
198
|
+
response_time,
|
|
199
|
+
error_message, error_stack, error_status_code,
|
|
200
|
+
timestamp
|
|
201
|
+
)
|
|
202
|
+
SELECT * FROM unnest(
|
|
203
|
+
$1::varchar[],
|
|
204
|
+
$2::varchar[],
|
|
205
|
+
$3::text[],
|
|
206
|
+
$4::text[],
|
|
207
|
+
$5::jsonb[],
|
|
208
|
+
$6::jsonb[],
|
|
209
|
+
$7::jsonb[],
|
|
210
|
+
$8::text[],
|
|
211
|
+
$9::integer[],
|
|
212
|
+
$10::varchar[],
|
|
213
|
+
$11::text[],
|
|
214
|
+
$12::smallint[],
|
|
215
|
+
$13::jsonb[],
|
|
216
|
+
$14::text[],
|
|
217
|
+
$15::integer[],
|
|
218
|
+
$16::real[],
|
|
219
|
+
$17::text[],
|
|
220
|
+
$18::text[],
|
|
221
|
+
$19::smallint[],
|
|
222
|
+
$20::varchar[]
|
|
223
|
+
)
|
|
224
|
+
`.trim();
|
|
225
|
+
await pool.query(sql, [
|
|
226
|
+
ids,
|
|
227
|
+
methods,
|
|
228
|
+
urls,
|
|
229
|
+
routes,
|
|
230
|
+
queryParams,
|
|
231
|
+
pathParams,
|
|
232
|
+
requestHeaders,
|
|
233
|
+
requestBodies,
|
|
234
|
+
requestBodySizes,
|
|
235
|
+
clientIps,
|
|
236
|
+
userAgents,
|
|
237
|
+
statusCodes,
|
|
238
|
+
responseHeaders,
|
|
239
|
+
responseBodies,
|
|
240
|
+
responseBodySizes,
|
|
241
|
+
responseTimes,
|
|
242
|
+
errorMessages,
|
|
243
|
+
errorStacks,
|
|
244
|
+
errorStatusCodes,
|
|
245
|
+
timestamps,
|
|
246
|
+
]);
|
|
247
|
+
}
|
|
248
|
+
// -------------------------------------------------------------------------
|
|
249
|
+
// query
|
|
250
|
+
// -------------------------------------------------------------------------
|
|
251
|
+
async query(filters, pagination) {
|
|
252
|
+
const pool = this.getPool();
|
|
253
|
+
const conditions = [];
|
|
254
|
+
const params = [];
|
|
255
|
+
let paramIdx = 1;
|
|
256
|
+
// Helper to add a parameter and return its $N placeholder
|
|
257
|
+
const addParam = (value) => {
|
|
258
|
+
params.push(value);
|
|
259
|
+
return `$${paramIdx++}`;
|
|
260
|
+
};
|
|
261
|
+
// id — exact match
|
|
262
|
+
if (filters.id !== undefined) {
|
|
263
|
+
conditions.push(`id = ${addParam(filters.id)}`);
|
|
264
|
+
}
|
|
265
|
+
// search — url ILIKE $N
|
|
266
|
+
if (filters.search !== undefined) {
|
|
267
|
+
conditions.push(`url ILIKE ${addParam(`%${filters.search}%`)}`);
|
|
268
|
+
}
|
|
269
|
+
// startDate — timestamp >= $N
|
|
270
|
+
if (filters.startDate !== undefined) {
|
|
271
|
+
conditions.push(`timestamp >= ${addParam(filters.startDate)}`);
|
|
272
|
+
}
|
|
273
|
+
// endDate — timestamp <= $N
|
|
274
|
+
if (filters.endDate !== undefined) {
|
|
275
|
+
conditions.push(`timestamp <= ${addParam(filters.endDate)}`);
|
|
276
|
+
}
|
|
277
|
+
// statusCode (exact, takes precedence over group)
|
|
278
|
+
if (filters.statusCode !== undefined) {
|
|
279
|
+
conditions.push(`status_code = ${addParam(filters.statusCode)}`);
|
|
280
|
+
}
|
|
281
|
+
else if (filters.statusCodeGroup !== undefined) {
|
|
282
|
+
const [min, max] = statusGroupRange(filters.statusCodeGroup);
|
|
283
|
+
conditions.push(`status_code >= ${addParam(min)} AND status_code < ${addParam(max)}`);
|
|
284
|
+
}
|
|
285
|
+
// method — case-insensitive
|
|
286
|
+
if (filters.method !== undefined) {
|
|
287
|
+
conditions.push(`LOWER(method) = LOWER(${addParam(filters.method)})`);
|
|
288
|
+
}
|
|
289
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
290
|
+
// Sort
|
|
291
|
+
const sortColRaw = filters.sortBy ?? 'timestamp';
|
|
292
|
+
const sortCol = SORT_COLUMN_MAP[sortColRaw] ?? 'timestamp';
|
|
293
|
+
const sortDir = (filters.sortOrder ?? 'desc').toUpperCase() === 'ASC' ? 'ASC' : 'DESC';
|
|
294
|
+
const orderClause = `ORDER BY ${sortCol} ${sortDir}`;
|
|
295
|
+
// COUNT query (reuses same params)
|
|
296
|
+
const countSql = `SELECT COUNT(*) AS total FROM requestscope_records ${whereClause}`;
|
|
297
|
+
const countResult = await pool.query(countSql, params);
|
|
298
|
+
const total = Number(countResult.rows[0]?.total ?? 0);
|
|
299
|
+
// Page slice — add LIMIT and OFFSET as the next params
|
|
300
|
+
const { page, pageSize } = pagination;
|
|
301
|
+
const offset = (Math.max(1, page) - 1) * pageSize;
|
|
302
|
+
const limitPlaceholder = addParam(pageSize);
|
|
303
|
+
const offsetPlaceholder = addParam(offset);
|
|
304
|
+
const dataSql = `
|
|
305
|
+
SELECT * FROM requestscope_records
|
|
306
|
+
${whereClause}
|
|
307
|
+
${orderClause}
|
|
308
|
+
LIMIT ${limitPlaceholder} OFFSET ${offsetPlaceholder}
|
|
309
|
+
`.trim();
|
|
310
|
+
const dataResult = await pool.query(dataSql, params);
|
|
311
|
+
const records = dataResult.rows.map(rowToRecord);
|
|
312
|
+
return { records, total };
|
|
313
|
+
}
|
|
314
|
+
// -------------------------------------------------------------------------
|
|
315
|
+
// deleteOlderThan
|
|
316
|
+
// -------------------------------------------------------------------------
|
|
317
|
+
async deleteOlderThan(date) {
|
|
318
|
+
const pool = this.getPool();
|
|
319
|
+
const iso = date.toISOString();
|
|
320
|
+
const result = await pool.query('DELETE FROM requestscope_records WHERE timestamp < $1', [iso]);
|
|
321
|
+
return result.rowCount ?? 0;
|
|
322
|
+
}
|
|
323
|
+
// -------------------------------------------------------------------------
|
|
324
|
+
// Private helpers
|
|
325
|
+
// -------------------------------------------------------------------------
|
|
326
|
+
getPool() {
|
|
327
|
+
if (this.pool === null) {
|
|
328
|
+
throw new Error('PgAdapter: call initialize() before using the adapter');
|
|
329
|
+
}
|
|
330
|
+
return this.pool;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
exports.PgAdapter = PgAdapter;
|
|
334
|
+
//# sourceMappingURL=pg.adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pg.adapter.js","sourceRoot":"","sources":["../../../src/adapters/pg.adapter.ts"],"names":[],"mappings":"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"}
|