@shadowcoderr/context-graph 0.3.3 → 0.3.5
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 +439 -88
- package/dist/analyzers/a11y-extractor.d.ts +19 -5
- package/dist/analyzers/a11y-extractor.d.ts.map +1 -1
- package/dist/analyzers/a11y-extractor.js +274 -104
- package/dist/analyzers/a11y-extractor.js.map +1 -1
- package/dist/analyzers/network-logger.d.ts +20 -2
- package/dist/analyzers/network-logger.d.ts.map +1 -1
- package/dist/analyzers/network-logger.js +122 -42
- package/dist/analyzers/network-logger.js.map +1 -1
- package/dist/analyzers/network-patterns.d.ts +73 -0
- package/dist/analyzers/network-patterns.d.ts.map +1 -0
- package/dist/analyzers/network-patterns.js +316 -0
- package/dist/analyzers/network-patterns.js.map +1 -0
- package/dist/analyzers/page-notifier.d.ts +40 -0
- package/dist/analyzers/page-notifier.d.ts.map +1 -0
- package/dist/analyzers/page-notifier.js +198 -0
- package/dist/analyzers/page-notifier.js.map +1 -0
- package/dist/analyzers/screenshot-capturer.d.ts +73 -0
- package/dist/analyzers/screenshot-capturer.d.ts.map +1 -0
- package/dist/analyzers/screenshot-capturer.js +190 -0
- package/dist/analyzers/screenshot-capturer.js.map +1 -0
- package/dist/cli/index.js +15 -6
- package/dist/cli/index.js.map +1 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +3 -1
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/schema.d.ts +8 -3
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +7 -2
- package/dist/config/schema.js.map +1 -1
- package/dist/core/browser-adapter.d.ts.map +1 -1
- package/dist/core/browser-adapter.js +0 -2
- package/dist/core/browser-adapter.js.map +1 -1
- package/dist/core/capture-engine.d.ts +30 -25
- package/dist/core/capture-engine.d.ts.map +1 -1
- package/dist/core/capture-engine.js +290 -276
- package/dist/core/capture-engine.js.map +1 -1
- package/dist/core/runtime.d.ts +1 -0
- package/dist/core/runtime.d.ts.map +1 -1
- package/dist/core/runtime.js +21 -0
- package/dist/core/runtime.js.map +1 -1
- package/dist/exporters/ai-context-bundler.d.ts +88 -0
- package/dist/exporters/ai-context-bundler.d.ts.map +1 -0
- package/dist/exporters/ai-context-bundler.js +380 -0
- package/dist/exporters/ai-context-bundler.js.map +1 -0
- package/dist/security/redactor.d.ts +16 -0
- package/dist/security/redactor.d.ts.map +1 -1
- package/dist/security/redactor.js +127 -57
- package/dist/security/redactor.js.map +1 -1
- package/dist/storage/engine.d.ts +24 -21
- package/dist/storage/engine.d.ts.map +1 -1
- package/dist/storage/engine.js +208 -175
- package/dist/storage/engine.js.map +1 -1
- package/dist/types/config.d.ts +4 -1
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/notifications.d.ts +37 -0
- package/dist/types/notifications.d.ts.map +1 -0
- package/dist/types/notifications.js +4 -0
- package/dist/types/notifications.js.map +1 -0
- package/package.json +71 -70
|
@@ -1,57 +1,130 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.NetworkLogger = void 0;
|
|
4
|
+
const logger_1 = require("../utils/logger");
|
|
5
|
+
const DEFAULT_OPTIONS = {
|
|
6
|
+
captureHeaders: true,
|
|
7
|
+
captureBody: false,
|
|
8
|
+
maxBodySize: 2048,
|
|
9
|
+
skipResourceTypes: ['image', 'font', 'media'],
|
|
10
|
+
};
|
|
4
11
|
class NetworkLogger {
|
|
5
12
|
events = [];
|
|
6
13
|
redactor;
|
|
7
|
-
|
|
8
|
-
|
|
14
|
+
options;
|
|
15
|
+
/**
|
|
16
|
+
* WeakMap keyed on the Playwright Request object guarantees O(1) access and
|
|
17
|
+
* zero URL collision — even when the same URL is requested concurrently.
|
|
18
|
+
* The Request object is the *same reference* in both the 'request' listener
|
|
19
|
+
* and the `response.request()` call, so this is safe.
|
|
20
|
+
*/
|
|
21
|
+
requestTimes = new WeakMap();
|
|
22
|
+
constructor(redactor, options) {
|
|
9
23
|
this.redactor = redactor;
|
|
24
|
+
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
10
25
|
}
|
|
11
26
|
async attachListeners(page) {
|
|
27
|
+
// ── Outgoing request ──────────────────────────────────────────────────────
|
|
12
28
|
page.on('request', async (request) => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
try {
|
|
30
|
+
if (this.options.skipResourceTypes.includes(request.resourceType()))
|
|
31
|
+
return;
|
|
32
|
+
this.requestTimes.set(request, Date.now());
|
|
33
|
+
const sanitizedUrl = this.redactor.sanitizeUrl(request.url());
|
|
34
|
+
const headers = this.options.captureHeaders ? { ...request.headers() } : {};
|
|
35
|
+
if (this.options.captureHeaders) {
|
|
36
|
+
await this.redactor.redact(headers, 'network_request', sanitizedUrl).catch(() => { });
|
|
37
|
+
}
|
|
38
|
+
const event = {
|
|
39
|
+
timestamp: new Date().toISOString(),
|
|
40
|
+
type: 'request',
|
|
41
|
+
method: request.method(),
|
|
42
|
+
url: sanitizedUrl,
|
|
43
|
+
resourceType: request.resourceType(),
|
|
44
|
+
headers,
|
|
45
|
+
timing: { startTime: Date.now() },
|
|
46
|
+
};
|
|
47
|
+
this.events.push(event);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
logger_1.logger.debug(`NetworkLogger request handler error: ${error.message}`);
|
|
51
|
+
}
|
|
30
52
|
});
|
|
53
|
+
// ── Response received ─────────────────────────────────────────────────────
|
|
31
54
|
page.on('response', async (response) => {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
try {
|
|
56
|
+
const request = response.request();
|
|
57
|
+
if (this.options.skipResourceTypes.includes(request.resourceType()))
|
|
58
|
+
return;
|
|
59
|
+
const endTime = Date.now();
|
|
60
|
+
const startTime = this.requestTimes.get(request) ?? endTime;
|
|
61
|
+
const duration = endTime - startTime;
|
|
62
|
+
// Do NOT delete from WeakMap — GC handles cleanup automatically
|
|
63
|
+
const sanitizedUrl = this.redactor.sanitizeUrl(response.url());
|
|
64
|
+
const headers = this.options.captureHeaders ? { ...response.headers() } : {};
|
|
65
|
+
if (this.options.captureHeaders) {
|
|
66
|
+
await this.redactor.redact(headers, 'network_response', sanitizedUrl).catch(() => { });
|
|
67
|
+
}
|
|
68
|
+
const event = {
|
|
69
|
+
timestamp: new Date().toISOString(),
|
|
70
|
+
type: 'response',
|
|
71
|
+
method: request.method(),
|
|
72
|
+
url: sanitizedUrl,
|
|
73
|
+
resourceType: request.resourceType(),
|
|
74
|
+
status: response.status(),
|
|
75
|
+
headers,
|
|
76
|
+
timing: { startTime, endTime, duration },
|
|
77
|
+
};
|
|
78
|
+
// Capture response body if enabled and content type is text/JSON
|
|
79
|
+
if (this.options.captureBody) {
|
|
80
|
+
const contentType = response.headers()['content-type'] ?? '';
|
|
81
|
+
const isText = contentType.includes('json') ||
|
|
82
|
+
contentType.includes('text/') ||
|
|
83
|
+
contentType.includes('xml');
|
|
84
|
+
if (isText) {
|
|
85
|
+
try {
|
|
86
|
+
const rawBody = await response.text();
|
|
87
|
+
if (rawBody) {
|
|
88
|
+
const bodyObj = { body: rawBody.substring(0, this.options.maxBodySize) };
|
|
89
|
+
await this.redactor.redact(bodyObj, 'response_body', sanitizedUrl).catch(() => { });
|
|
90
|
+
event.body = bodyObj.body;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Body may not be readable (e.g. already consumed); skip silently
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
this.events.push(event);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
logger_1.logger.debug(`NetworkLogger response handler error: ${error.message}`);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
// ── Failed request — captured as type 'failed' ────────────────────────────
|
|
105
|
+
page.on('requestfailed', async (request) => {
|
|
106
|
+
try {
|
|
107
|
+
if (this.options.skipResourceTypes.includes(request.resourceType()))
|
|
108
|
+
return;
|
|
109
|
+
const endTime = Date.now();
|
|
110
|
+
const startTime = this.requestTimes.get(request) ?? endTime;
|
|
111
|
+
const sanitizedUrl = this.redactor.sanitizeUrl(request.url());
|
|
112
|
+
const event = {
|
|
113
|
+
timestamp: new Date().toISOString(),
|
|
114
|
+
type: 'failed',
|
|
115
|
+
method: request.method(),
|
|
116
|
+
url: sanitizedUrl,
|
|
117
|
+
resourceType: request.resourceType(),
|
|
118
|
+
failureReason: request.failure()?.errorText ?? 'Unknown failure',
|
|
119
|
+
timing: { startTime, endTime, duration: endTime - startTime },
|
|
120
|
+
headers: {},
|
|
121
|
+
};
|
|
122
|
+
this.events.push(event);
|
|
123
|
+
logger_1.logger.debug(`Network request failed: ${request.method()} ${sanitizedUrl} — ${event.failureReason}`);
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
logger_1.logger.debug(`NetworkLogger requestfailed handler error: ${error.message}`);
|
|
127
|
+
}
|
|
55
128
|
});
|
|
56
129
|
}
|
|
57
130
|
getEvents() {
|
|
@@ -66,6 +139,13 @@ class NetworkLogger {
|
|
|
66
139
|
getResponseCount() {
|
|
67
140
|
return this.events.filter(e => e.type === 'response').length;
|
|
68
141
|
}
|
|
142
|
+
getFailedCount() {
|
|
143
|
+
return this.events.filter(e => e.type === 'failed').length;
|
|
144
|
+
}
|
|
145
|
+
/** Returns only XHR/Fetch events — useful for API surface analysis */
|
|
146
|
+
getApiEvents() {
|
|
147
|
+
return this.events.filter(e => e.resourceType === 'xhr' || e.resourceType === 'fetch');
|
|
148
|
+
}
|
|
69
149
|
}
|
|
70
150
|
exports.NetworkLogger = NetworkLogger;
|
|
71
151
|
//# sourceMappingURL=network-logger.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network-logger.js","sourceRoot":"","sources":["../../src/analyzers/network-logger.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"network-logger.js","sourceRoot":"","sources":["../../src/analyzers/network-logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { NetworkEvent } from '../types/capture';
|
|
2
|
+
export interface ApiEndpoint {
|
|
3
|
+
method: string;
|
|
4
|
+
/** Normalised path with path-parameter placeholders, e.g. /users/{id}/orders */
|
|
5
|
+
path: string;
|
|
6
|
+
/** Raw paths observed before normalisation */
|
|
7
|
+
rawPaths: string[];
|
|
8
|
+
observedCount: number;
|
|
9
|
+
statusCodes: number[];
|
|
10
|
+
avgDurationMs: number | null;
|
|
11
|
+
hasRequestBody: boolean;
|
|
12
|
+
hasResponseBody: boolean;
|
|
13
|
+
contentTypes: string[];
|
|
14
|
+
firstSeen: string;
|
|
15
|
+
lastSeen: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ApiInventory {
|
|
18
|
+
version: string;
|
|
19
|
+
generatedAt: string;
|
|
20
|
+
baseUrl: string | null;
|
|
21
|
+
capturedDuration: string;
|
|
22
|
+
totalRequests: number;
|
|
23
|
+
totalFailedRequests: number;
|
|
24
|
+
uniqueEndpoints: number;
|
|
25
|
+
endpoints: ApiEndpoint[];
|
|
26
|
+
resourceBreakdown: Record<string, number>;
|
|
27
|
+
statusCodeBreakdown: Record<string, number>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* NetworkPatternAnalyzer
|
|
31
|
+
*
|
|
32
|
+
* Post-processes captured network events to produce a structured API inventory.
|
|
33
|
+
* Duplicate URLs are deduplicated, path parameters (numeric IDs, UUIDs, etc.)
|
|
34
|
+
* are normalised into `{param}` placeholders, and status codes / durations
|
|
35
|
+
* are aggregated per endpoint.
|
|
36
|
+
*
|
|
37
|
+
* Usage:
|
|
38
|
+
*
|
|
39
|
+
* const analyzer = new NetworkPatternAnalyzer(outputDir);
|
|
40
|
+
* const inventory = await analyzer.analyze();
|
|
41
|
+
* // → context-graph-output/<domain>/api_inventory.json
|
|
42
|
+
*
|
|
43
|
+
* Or pass raw NetworkEvents directly:
|
|
44
|
+
*
|
|
45
|
+
* const inventory = analyzer.analyzeEvents(events, 'https://api.example.com');
|
|
46
|
+
*/
|
|
47
|
+
export declare class NetworkPatternAnalyzer {
|
|
48
|
+
private outputDir;
|
|
49
|
+
constructor(outputDir: string);
|
|
50
|
+
/**
|
|
51
|
+
* Read all captured network traffic from the output directory, analyse it,
|
|
52
|
+
* and write an `api_inventory.json` file to the domain directory.
|
|
53
|
+
* Returns the path to the generated file.
|
|
54
|
+
*/
|
|
55
|
+
analyze(): Promise<string>;
|
|
56
|
+
/**
|
|
57
|
+
* Analyse an in-memory array of NetworkEvents and return an ApiInventory.
|
|
58
|
+
* Does NOT write to disk — useful for programmatic / test use.
|
|
59
|
+
*/
|
|
60
|
+
analyzeEvents(events: NetworkEvent[], baseUrl?: string | null): ApiInventory;
|
|
61
|
+
/**
|
|
62
|
+
* Normalise a URL path by replacing dynamic segments with typed placeholders.
|
|
63
|
+
*
|
|
64
|
+
* /users/12345/orders/abc123 → /users/{id}/orders/{token}
|
|
65
|
+
* /api/v2/items/6452 → /api/v2/items/{id}
|
|
66
|
+
*/
|
|
67
|
+
normalisePath(urlPath: string): string;
|
|
68
|
+
private loadEventsFromJSONL;
|
|
69
|
+
private detectDomain;
|
|
70
|
+
private detectBaseUrl;
|
|
71
|
+
private computeDuration;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=network-patterns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-patterns.d.ts","sourceRoot":"","sources":["../../src/analyzers/network-patterns.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIhD,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc,EAAE,OAAO,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;IACzB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,WAAW,EAAE,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7C;AAiBD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,SAAS,CAAS;gBAEd,SAAS,EAAE,MAAM;IAM7B;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;IAuBhC;;;OAGG;IACH,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,OAAO,GAAE,MAAM,GAAG,IAAW,GAAG,YAAY;IA4HlF;;;;;OAKG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;YAkBxB,mBAAmB;IAsBjC,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,aAAa;IAuBrB,OAAO,CAAC,eAAe;CAmBxB"}
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.NetworkPatternAnalyzer = void 0;
|
|
37
|
+
// Developer: Shadow Coderr, Architect
|
|
38
|
+
const fs = __importStar(require("fs-extra"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const logger_1 = require("../utils/logger");
|
|
41
|
+
const version_1 = require("../utils/version");
|
|
42
|
+
/**
|
|
43
|
+
* Patterns that identify path segments as dynamic parameters.
|
|
44
|
+
* Matched in order — first match wins.
|
|
45
|
+
*/
|
|
46
|
+
const PARAM_PATTERNS = [
|
|
47
|
+
{
|
|
48
|
+
regex: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
|
|
49
|
+
placeholder: '{uuid}',
|
|
50
|
+
},
|
|
51
|
+
{ regex: /^\d{10,}$/, placeholder: '{timestamp}' },
|
|
52
|
+
{ regex: /^\d+$/, placeholder: '{id}' },
|
|
53
|
+
{ regex: /^[0-9a-f]{24}$/, placeholder: '{objectid}' }, // MongoDB ObjectId
|
|
54
|
+
{ regex: /^[0-9a-zA-Z_-]{20,}$/, placeholder: '{token}' },
|
|
55
|
+
];
|
|
56
|
+
/**
|
|
57
|
+
* NetworkPatternAnalyzer
|
|
58
|
+
*
|
|
59
|
+
* Post-processes captured network events to produce a structured API inventory.
|
|
60
|
+
* Duplicate URLs are deduplicated, path parameters (numeric IDs, UUIDs, etc.)
|
|
61
|
+
* are normalised into `{param}` placeholders, and status codes / durations
|
|
62
|
+
* are aggregated per endpoint.
|
|
63
|
+
*
|
|
64
|
+
* Usage:
|
|
65
|
+
*
|
|
66
|
+
* const analyzer = new NetworkPatternAnalyzer(outputDir);
|
|
67
|
+
* const inventory = await analyzer.analyze();
|
|
68
|
+
* // → context-graph-output/<domain>/api_inventory.json
|
|
69
|
+
*
|
|
70
|
+
* Or pass raw NetworkEvents directly:
|
|
71
|
+
*
|
|
72
|
+
* const inventory = analyzer.analyzeEvents(events, 'https://api.example.com');
|
|
73
|
+
*/
|
|
74
|
+
class NetworkPatternAnalyzer {
|
|
75
|
+
outputDir;
|
|
76
|
+
constructor(outputDir) {
|
|
77
|
+
this.outputDir = path.resolve(outputDir);
|
|
78
|
+
}
|
|
79
|
+
// ── Public API ────────────────────────────────────────────────────────────────
|
|
80
|
+
/**
|
|
81
|
+
* Read all captured network traffic from the output directory, analyse it,
|
|
82
|
+
* and write an `api_inventory.json` file to the domain directory.
|
|
83
|
+
* Returns the path to the generated file.
|
|
84
|
+
*/
|
|
85
|
+
async analyze() {
|
|
86
|
+
const domain = this.detectDomain();
|
|
87
|
+
if (!domain)
|
|
88
|
+
throw new Error('No captured domain found');
|
|
89
|
+
const trafficLog = path.join(this.outputDir, domain, 'network', 'traffic_log.jsonl');
|
|
90
|
+
const events = await this.loadEventsFromJSONL(trafficLog);
|
|
91
|
+
if (events.length === 0) {
|
|
92
|
+
logger_1.logger.warn('NetworkPatternAnalyzer: no network events found, generating empty inventory');
|
|
93
|
+
}
|
|
94
|
+
// Determine base URL from the most common hostname
|
|
95
|
+
const baseUrl = this.detectBaseUrl(events);
|
|
96
|
+
const inventory = this.analyzeEvents(events, baseUrl);
|
|
97
|
+
const outputPath = path.join(this.outputDir, domain, 'api_inventory.json');
|
|
98
|
+
await fs.writeJson(outputPath, inventory, { spaces: 2 });
|
|
99
|
+
logger_1.logger.info(`NetworkPatternAnalyzer: API inventory saved to ${outputPath}`);
|
|
100
|
+
return outputPath;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Analyse an in-memory array of NetworkEvents and return an ApiInventory.
|
|
104
|
+
* Does NOT write to disk — useful for programmatic / test use.
|
|
105
|
+
*/
|
|
106
|
+
analyzeEvents(events, baseUrl = null) {
|
|
107
|
+
const apiEvents = events.filter(e => e.type === 'request' && (e.resourceType === 'xhr' || e.resourceType === 'fetch'));
|
|
108
|
+
console.log(`Found ${apiEvents.length} API events`);
|
|
109
|
+
// Build response lookup keyed by method + url
|
|
110
|
+
const responseMap = new Map();
|
|
111
|
+
for (const e of events) {
|
|
112
|
+
if (e.type === 'response') {
|
|
113
|
+
responseMap.set(`${e.method}|${e.url}`, e);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Aggregate by normalised endpoint
|
|
117
|
+
const endpointMap = new Map();
|
|
118
|
+
const resourceCounts = {};
|
|
119
|
+
const statusCounts = {};
|
|
120
|
+
const firstTimestamp = events[0]?.timestamp ?? new Date().toISOString();
|
|
121
|
+
const lastTimestamp = events[events.length - 1]?.timestamp ?? firstTimestamp;
|
|
122
|
+
for (const event of events) {
|
|
123
|
+
// Resource type breakdown (all events)
|
|
124
|
+
resourceCounts[event.resourceType] = (resourceCounts[event.resourceType] || 0) + 1;
|
|
125
|
+
if (event.type !== 'request')
|
|
126
|
+
continue;
|
|
127
|
+
// Parse and normalise the URL path
|
|
128
|
+
let parsedPath;
|
|
129
|
+
let host;
|
|
130
|
+
try {
|
|
131
|
+
const u = new URL(event.url);
|
|
132
|
+
parsedPath = u.pathname;
|
|
133
|
+
host = u.hostname;
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
continue; // unparseable
|
|
137
|
+
}
|
|
138
|
+
const normalised = this.normalisePath(parsedPath);
|
|
139
|
+
const key = `${event.method}||${host}||${normalised}`;
|
|
140
|
+
const response = responseMap.get(`${event.method}|${event.url}`);
|
|
141
|
+
const status = response?.status;
|
|
142
|
+
const duration = response?.timing?.duration ?? null;
|
|
143
|
+
if (status !== undefined) {
|
|
144
|
+
const statusKey = `${Math.floor(status / 100)}xx`;
|
|
145
|
+
statusCounts[statusKey] = (statusCounts[statusKey] || 0) + 1;
|
|
146
|
+
}
|
|
147
|
+
let ep = endpointMap.get(key);
|
|
148
|
+
if (!ep) {
|
|
149
|
+
ep = {
|
|
150
|
+
method: event.method,
|
|
151
|
+
path: normalised,
|
|
152
|
+
rawPaths: [],
|
|
153
|
+
observedCount: 0,
|
|
154
|
+
statusCodes: [],
|
|
155
|
+
avgDurationMs: null,
|
|
156
|
+
hasRequestBody: false,
|
|
157
|
+
hasResponseBody: false,
|
|
158
|
+
contentTypes: [],
|
|
159
|
+
firstSeen: event.timestamp,
|
|
160
|
+
lastSeen: event.timestamp,
|
|
161
|
+
};
|
|
162
|
+
endpointMap.set(key, ep);
|
|
163
|
+
}
|
|
164
|
+
ep.observedCount++;
|
|
165
|
+
if (!ep.rawPaths.includes(parsedPath))
|
|
166
|
+
ep.rawPaths.push(parsedPath);
|
|
167
|
+
if (status !== undefined && !ep.statusCodes.includes(status)) {
|
|
168
|
+
ep.statusCodes.push(status);
|
|
169
|
+
}
|
|
170
|
+
if (duration !== null) {
|
|
171
|
+
if (ep.avgDurationMs === null) {
|
|
172
|
+
ep.avgDurationMs = duration;
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
ep.avgDurationMs = Math.round((ep.avgDurationMs + duration) / 2);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const ct = event.headers?.['content-type'] || response?.headers?.['content-type'] || '';
|
|
179
|
+
if (ct && !ep.contentTypes.includes(ct.split(';')[0].trim())) {
|
|
180
|
+
ep.contentTypes.push(ct.split(';')[0].trim());
|
|
181
|
+
}
|
|
182
|
+
ep.hasRequestBody =
|
|
183
|
+
ep.hasRequestBody || ['POST', 'PUT', 'PATCH'].includes(event.method);
|
|
184
|
+
ep.hasResponseBody = ep.hasResponseBody || Boolean(response && status && status < 400);
|
|
185
|
+
if (event.timestamp < ep.firstSeen)
|
|
186
|
+
ep.firstSeen = event.timestamp;
|
|
187
|
+
if (event.timestamp > ep.lastSeen)
|
|
188
|
+
ep.lastSeen = event.timestamp;
|
|
189
|
+
}
|
|
190
|
+
const endpoints = Array.from(endpointMap.values()).sort((a, b) => {
|
|
191
|
+
// Sort by HTTP method priority, then alphabetically by path
|
|
192
|
+
const methodOrder = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
|
|
193
|
+
const ai = methodOrder.indexOf(a.method);
|
|
194
|
+
const bi = methodOrder.indexOf(b.method);
|
|
195
|
+
if (ai !== bi)
|
|
196
|
+
return ai - bi;
|
|
197
|
+
return a.path.localeCompare(b.path);
|
|
198
|
+
});
|
|
199
|
+
const failedRequests = events.filter(e => e.type === 'failed').length;
|
|
200
|
+
return {
|
|
201
|
+
version: (0, version_1.getVersion)(),
|
|
202
|
+
generatedAt: new Date().toISOString(),
|
|
203
|
+
baseUrl,
|
|
204
|
+
capturedDuration: this.computeDuration(firstTimestamp, lastTimestamp),
|
|
205
|
+
totalRequests: events.filter(e => e.type === 'request').length,
|
|
206
|
+
totalFailedRequests: failedRequests,
|
|
207
|
+
uniqueEndpoints: endpoints.length,
|
|
208
|
+
endpoints,
|
|
209
|
+
resourceBreakdown: resourceCounts,
|
|
210
|
+
statusCodeBreakdown: statusCounts,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
// ── Private helpers ──────────────────────────────────────────────────────────
|
|
214
|
+
/**
|
|
215
|
+
* Normalise a URL path by replacing dynamic segments with typed placeholders.
|
|
216
|
+
*
|
|
217
|
+
* /users/12345/orders/abc123 → /users/{id}/orders/{token}
|
|
218
|
+
* /api/v2/items/6452 → /api/v2/items/{id}
|
|
219
|
+
*/
|
|
220
|
+
normalisePath(urlPath) {
|
|
221
|
+
if (!urlPath)
|
|
222
|
+
return '/';
|
|
223
|
+
const segments = urlPath.split('/').filter(Boolean);
|
|
224
|
+
const normalised = segments.map(segment => {
|
|
225
|
+
// Decode percent-encoded characters before testing
|
|
226
|
+
let decoded = segment;
|
|
227
|
+
try {
|
|
228
|
+
decoded = decodeURIComponent(segment);
|
|
229
|
+
}
|
|
230
|
+
catch { /* leave as-is */ }
|
|
231
|
+
for (const { regex, placeholder } of PARAM_PATTERNS) {
|
|
232
|
+
if (regex.test(decoded))
|
|
233
|
+
return placeholder;
|
|
234
|
+
}
|
|
235
|
+
return segment;
|
|
236
|
+
});
|
|
237
|
+
return '/' + normalised.join('/');
|
|
238
|
+
}
|
|
239
|
+
async loadEventsFromJSONL(filePath) {
|
|
240
|
+
if (!(await fs.pathExists(filePath))) {
|
|
241
|
+
logger_1.logger.warn(`NetworkPatternAnalyzer: traffic log not found at ${filePath}`);
|
|
242
|
+
return [];
|
|
243
|
+
}
|
|
244
|
+
const raw = await fs.readFile(filePath, 'utf8');
|
|
245
|
+
const events = [];
|
|
246
|
+
for (const line of raw.split('\n')) {
|
|
247
|
+
const trimmed = line.trim();
|
|
248
|
+
if (!trimmed)
|
|
249
|
+
continue;
|
|
250
|
+
try {
|
|
251
|
+
events.push(JSON.parse(trimmed));
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
logger_1.logger.debug(`NetworkPatternAnalyzer: skipping malformed line: ${trimmed.substring(0, 80)}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return events;
|
|
258
|
+
}
|
|
259
|
+
detectDomain() {
|
|
260
|
+
try {
|
|
261
|
+
const entries = fs.readdirSync(this.outputDir, { withFileTypes: true });
|
|
262
|
+
const domainDir = entries.find(e => e.isDirectory() && !['scripts', 'bundles', 'logs'].includes(e.name));
|
|
263
|
+
return domainDir?.name || null;
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
detectBaseUrl(events) {
|
|
270
|
+
const hostCounts = new Map();
|
|
271
|
+
for (const e of events) {
|
|
272
|
+
if (e.type !== 'request')
|
|
273
|
+
continue;
|
|
274
|
+
try {
|
|
275
|
+
const u = new URL(e.url);
|
|
276
|
+
const key = `${u.protocol}//${u.host}`;
|
|
277
|
+
hostCounts.set(key, (hostCounts.get(key) || 0) + 1);
|
|
278
|
+
}
|
|
279
|
+
catch { /* skip */ }
|
|
280
|
+
}
|
|
281
|
+
if (hostCounts.size === 0)
|
|
282
|
+
return null;
|
|
283
|
+
let topHost = '';
|
|
284
|
+
let topCount = 0;
|
|
285
|
+
for (const [host, count] of hostCounts.entries()) {
|
|
286
|
+
if (count > topCount) {
|
|
287
|
+
topHost = host;
|
|
288
|
+
topCount = count;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return topHost || null;
|
|
292
|
+
}
|
|
293
|
+
computeDuration(start, end) {
|
|
294
|
+
try {
|
|
295
|
+
const ms = new Date(end).getTime() - new Date(start).getTime();
|
|
296
|
+
if (ms < 0)
|
|
297
|
+
return 'unknown';
|
|
298
|
+
const totalSeconds = Math.floor(ms / 1000);
|
|
299
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
300
|
+
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
301
|
+
const seconds = totalSeconds % 60;
|
|
302
|
+
const parts = [];
|
|
303
|
+
if (hours > 0)
|
|
304
|
+
parts.push(`${hours}h`);
|
|
305
|
+
if (minutes > 0)
|
|
306
|
+
parts.push(`${minutes}m`);
|
|
307
|
+
parts.push(`${seconds}s`);
|
|
308
|
+
return parts.join(' ');
|
|
309
|
+
}
|
|
310
|
+
catch {
|
|
311
|
+
return 'unknown';
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
exports.NetworkPatternAnalyzer = NetworkPatternAnalyzer;
|
|
316
|
+
//# sourceMappingURL=network-patterns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-patterns.js","sourceRoot":"","sources":["../../src/analyzers/network-patterns.ts"],"names":[],"mappings":"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"}
|