real-browser-mcp-server 1.4.5 → 1.5.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 +6 -10
- package/dist/lib/cjs/index.js +2 -381
- package/dist/lib/cjs/index.js.map +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -20
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/handlers/browser.d.ts.map +1 -1
- package/dist/src/mcp/handlers/browser.js +3 -2
- package/dist/src/mcp/handlers/browser.js.map +1 -1
- package/dist/src/mcp/handlers/dom.d.ts +7 -80
- package/dist/src/mcp/handlers/dom.d.ts.map +1 -1
- package/dist/src/mcp/handlers/dom.js +46 -190
- package/dist/src/mcp/handlers/dom.js.map +1 -1
- package/dist/src/mcp/handlers/extract.d.ts +47 -22
- package/dist/src/mcp/handlers/extract.d.ts.map +1 -1
- package/dist/src/mcp/handlers/extract.js +66 -269
- package/dist/src/mcp/handlers/extract.js.map +1 -1
- package/dist/src/mcp/handlers/helpers.d.ts +18 -3
- package/dist/src/mcp/handlers/helpers.d.ts.map +1 -1
- package/dist/src/mcp/handlers/helpers.js +56 -176
- package/dist/src/mcp/handlers/helpers.js.map +1 -1
- package/dist/src/mcp/handlers/index.d.ts.map +1 -1
- package/dist/src/mcp/handlers/index.js +1 -3
- package/dist/src/mcp/handlers/index.js.map +1 -1
- package/dist/src/mcp/handlers/media-handlers.d.ts +5 -6
- package/dist/src/mcp/handlers/media-handlers.d.ts.map +1 -1
- package/dist/src/mcp/handlers/media-handlers.js +1 -69
- package/dist/src/mcp/handlers/media-handlers.js.map +1 -1
- package/dist/src/mcp/handlers/network.d.ts +95 -12
- package/dist/src/mcp/handlers/network.d.ts.map +1 -1
- package/dist/src/mcp/handlers/network.js +178 -49
- package/dist/src/mcp/handlers/network.js.map +1 -1
- package/dist/src/mcp/handlers/utility-handlers.d.ts +36 -102
- package/dist/src/mcp/handlers/utility-handlers.d.ts.map +1 -1
- package/dist/src/mcp/handlers/utility-handlers.js +93 -177
- package/dist/src/mcp/handlers/utility-handlers.js.map +1 -1
- package/dist/src/mcp/handlers/vision.d.ts +143 -41
- package/dist/src/mcp/handlers/vision.d.ts.map +1 -1
- package/dist/src/mcp/handlers/vision.js +155 -88
- package/dist/src/mcp/handlers/vision.js.map +1 -1
- package/dist/src/mcp/index.d.ts.map +1 -1
- package/dist/src/mcp/index.js +2 -13
- package/dist/src/mcp/index.js.map +1 -1
- package/dist/src/mcp/server.d.ts.map +1 -1
- package/dist/src/mcp/server.js +1 -5
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/shared/colors.d.ts +12 -0
- package/dist/src/shared/colors.d.ts.map +1 -0
- package/dist/src/shared/colors.js +15 -0
- package/dist/src/shared/colors.js.map +1 -0
- package/dist/src/shared/lib-core.d.ts +17 -0
- package/dist/src/shared/lib-core.d.ts.map +1 -0
- package/dist/src/shared/lib-core.js +421 -0
- package/dist/src/shared/lib-core.js.map +1 -0
- package/dist/src/shared/tools.d.ts.map +1 -1
- package/dist/src/shared/tools.js +90 -132
- package/dist/src/shared/tools.js.map +1 -1
- package/dist/test/cjs/test.js +61 -104
- package/dist/test/cjs/test.js.map +1 -1
- package/lib/esm/index.mjs +2 -396
- package/package.json +1 -1
- package/dist/src/mcp/handlers/form-handlers.d.ts +0 -9
- package/dist/src/mcp/handlers/form-handlers.d.ts.map +0 -1
- package/dist/src/mcp/handlers/form-handlers.js +0 -56
- package/dist/src/mcp/handlers/form-handlers.js.map +0 -1
- package/dist/src/mcp/tools.d.ts +0 -8
- package/dist/src/mcp/tools.d.ts.map +0 -1
- package/dist/src/mcp/tools.js +0 -19
- package/dist/src/mcp/tools.js.map +0 -1
|
@@ -22,6 +22,8 @@ export declare const networkHandlers: {
|
|
|
22
22
|
error?: undefined;
|
|
23
23
|
totalMessages?: undefined;
|
|
24
24
|
websockets?: undefined;
|
|
25
|
+
graphql?: undefined;
|
|
26
|
+
har?: undefined;
|
|
25
27
|
recording?: undefined;
|
|
26
28
|
records?: undefined;
|
|
27
29
|
} | {
|
|
@@ -35,6 +37,8 @@ export declare const networkHandlers: {
|
|
|
35
37
|
error?: undefined;
|
|
36
38
|
totalMessages?: undefined;
|
|
37
39
|
websockets?: undefined;
|
|
40
|
+
graphql?: undefined;
|
|
41
|
+
har?: undefined;
|
|
38
42
|
recording?: undefined;
|
|
39
43
|
records?: undefined;
|
|
40
44
|
} | {
|
|
@@ -58,6 +62,8 @@ export declare const networkHandlers: {
|
|
|
58
62
|
error?: undefined;
|
|
59
63
|
totalMessages?: undefined;
|
|
60
64
|
websockets?: undefined;
|
|
65
|
+
graphql?: undefined;
|
|
66
|
+
har?: undefined;
|
|
61
67
|
recording?: undefined;
|
|
62
68
|
records?: undefined;
|
|
63
69
|
} | {
|
|
@@ -71,6 +77,8 @@ export declare const networkHandlers: {
|
|
|
71
77
|
error?: undefined;
|
|
72
78
|
totalMessages?: undefined;
|
|
73
79
|
websockets?: undefined;
|
|
80
|
+
graphql?: undefined;
|
|
81
|
+
har?: undefined;
|
|
74
82
|
recording?: undefined;
|
|
75
83
|
records?: undefined;
|
|
76
84
|
} | {
|
|
@@ -84,6 +92,8 @@ export declare const networkHandlers: {
|
|
|
84
92
|
note?: undefined;
|
|
85
93
|
totalMessages?: undefined;
|
|
86
94
|
websockets?: undefined;
|
|
95
|
+
graphql?: undefined;
|
|
96
|
+
har?: undefined;
|
|
87
97
|
recording?: undefined;
|
|
88
98
|
records?: undefined;
|
|
89
99
|
} | {
|
|
@@ -97,6 +107,8 @@ export declare const networkHandlers: {
|
|
|
97
107
|
apiCalls?: undefined;
|
|
98
108
|
interceptedApis?: undefined;
|
|
99
109
|
error?: undefined;
|
|
110
|
+
graphql?: undefined;
|
|
111
|
+
har?: undefined;
|
|
100
112
|
recording?: undefined;
|
|
101
113
|
records?: undefined;
|
|
102
114
|
} | {
|
|
@@ -110,13 +122,22 @@ export declare const networkHandlers: {
|
|
|
110
122
|
interceptedApis?: undefined;
|
|
111
123
|
note?: undefined;
|
|
112
124
|
totalMessages?: undefined;
|
|
125
|
+
graphql?: undefined;
|
|
126
|
+
har?: undefined;
|
|
113
127
|
recording?: undefined;
|
|
114
128
|
records?: undefined;
|
|
115
129
|
} | {
|
|
116
130
|
success: boolean;
|
|
117
|
-
recording: boolean;
|
|
118
131
|
count: number;
|
|
119
|
-
|
|
132
|
+
graphql: {
|
|
133
|
+
url: any;
|
|
134
|
+
method: any;
|
|
135
|
+
operationName: any;
|
|
136
|
+
query: any;
|
|
137
|
+
variables: any;
|
|
138
|
+
response: any;
|
|
139
|
+
timestamp: any;
|
|
140
|
+
}[];
|
|
120
141
|
mediaUrls?: undefined;
|
|
121
142
|
navigations?: undefined;
|
|
122
143
|
apiCalls?: undefined;
|
|
@@ -125,23 +146,85 @@ export declare const networkHandlers: {
|
|
|
125
146
|
error?: undefined;
|
|
126
147
|
totalMessages?: undefined;
|
|
127
148
|
websockets?: undefined;
|
|
128
|
-
|
|
129
|
-
|
|
149
|
+
har?: undefined;
|
|
150
|
+
recording?: undefined;
|
|
151
|
+
records?: undefined;
|
|
152
|
+
} | {
|
|
130
153
|
success: boolean;
|
|
131
|
-
|
|
132
|
-
|
|
154
|
+
count: number;
|
|
155
|
+
har: {
|
|
156
|
+
log: {
|
|
157
|
+
version: string;
|
|
158
|
+
creator: {
|
|
159
|
+
name: string;
|
|
160
|
+
version: string;
|
|
161
|
+
};
|
|
162
|
+
entries: {
|
|
163
|
+
startedDateTime: string;
|
|
164
|
+
request: {
|
|
165
|
+
method: any;
|
|
166
|
+
url: any;
|
|
167
|
+
headers: {
|
|
168
|
+
name: string;
|
|
169
|
+
value: string;
|
|
170
|
+
}[];
|
|
171
|
+
postData: {
|
|
172
|
+
text: any;
|
|
173
|
+
} | undefined;
|
|
174
|
+
};
|
|
175
|
+
response: {
|
|
176
|
+
status: any;
|
|
177
|
+
content: {
|
|
178
|
+
mimeType: any;
|
|
179
|
+
text: any;
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
time: number;
|
|
183
|
+
}[];
|
|
184
|
+
};
|
|
185
|
+
};
|
|
186
|
+
mediaUrls?: undefined;
|
|
187
|
+
navigations?: undefined;
|
|
188
|
+
apiCalls?: undefined;
|
|
189
|
+
interceptedApis?: undefined;
|
|
190
|
+
note?: undefined;
|
|
133
191
|
error?: undefined;
|
|
192
|
+
totalMessages?: undefined;
|
|
193
|
+
websockets?: undefined;
|
|
194
|
+
graphql?: undefined;
|
|
195
|
+
recording?: undefined;
|
|
196
|
+
records?: undefined;
|
|
134
197
|
} | {
|
|
135
198
|
success: boolean;
|
|
136
|
-
|
|
137
|
-
|
|
199
|
+
recording: boolean;
|
|
200
|
+
count: number;
|
|
201
|
+
records: import("../../types").NetworkRecord[];
|
|
202
|
+
mediaUrls?: undefined;
|
|
203
|
+
navigations?: undefined;
|
|
204
|
+
apiCalls?: undefined;
|
|
205
|
+
interceptedApis?: undefined;
|
|
206
|
+
note?: undefined;
|
|
207
|
+
error?: undefined;
|
|
208
|
+
totalMessages?: undefined;
|
|
209
|
+
websockets?: undefined;
|
|
210
|
+
graphql?: undefined;
|
|
211
|
+
har?: undefined;
|
|
212
|
+
}>;
|
|
213
|
+
extract_data(params?: any): Promise<any>;
|
|
214
|
+
replay_request(params: any): Promise<{
|
|
215
|
+
success: boolean;
|
|
216
|
+
result: {
|
|
217
|
+
status: number;
|
|
218
|
+
headers: {
|
|
219
|
+
[k: string]: string;
|
|
220
|
+
};
|
|
221
|
+
body: string | null;
|
|
222
|
+
};
|
|
138
223
|
error?: undefined;
|
|
139
224
|
} | {
|
|
140
225
|
success: boolean;
|
|
141
|
-
error:
|
|
142
|
-
|
|
143
|
-
message?: undefined;
|
|
226
|
+
error: any;
|
|
227
|
+
result?: undefined;
|
|
144
228
|
}>;
|
|
145
|
-
extract_data(params?: any): Promise<any>;
|
|
146
229
|
};
|
|
147
230
|
//# sourceMappingURL=network.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../../../src/mcp/handlers/network.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../../../src/mcp/handlers/network.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,eAAe;4BACI,GAAG;;;;;;;;;8BAiHF,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BA4WP,GAAG;2BA6wBD,GAAG;;;;;;;;;;;;;;;CAuBjC,CAAC"}
|
|
@@ -401,6 +401,57 @@ exports.networkHandlers = {
|
|
|
401
401
|
return { success: false, error: 'Failed to retrieve WebSocket data: ' + e.message, websockets: [] };
|
|
402
402
|
}
|
|
403
403
|
}
|
|
404
|
+
// ====== FEATURE 4: GraphQL Inspector ======
|
|
405
|
+
case 'get_graphql': {
|
|
406
|
+
const gqlRecords = state_1.state.networkRecords.filter((r) => r.isApiCall && r.requestBody && (r.requestBody.includes('"query"') || r.requestBody.includes('query '))).map((r) => {
|
|
407
|
+
let parsedQuery = null, parsedVariables = null, operationName = null;
|
|
408
|
+
try {
|
|
409
|
+
const body = JSON.parse(r.requestBody);
|
|
410
|
+
parsedQuery = body.query;
|
|
411
|
+
parsedVariables = body.variables;
|
|
412
|
+
operationName = body.operationName;
|
|
413
|
+
}
|
|
414
|
+
catch (e) { }
|
|
415
|
+
return {
|
|
416
|
+
url: r.url,
|
|
417
|
+
method: r.method,
|
|
418
|
+
operationName: operationName || 'unknown',
|
|
419
|
+
query: parsedQuery || r.requestBody,
|
|
420
|
+
variables: parsedVariables,
|
|
421
|
+
response: r.responseJson || r.responseBody,
|
|
422
|
+
timestamp: r.timestamp
|
|
423
|
+
};
|
|
424
|
+
});
|
|
425
|
+
return { success: true, count: gqlRecords.length, graphql: gqlRecords };
|
|
426
|
+
}
|
|
427
|
+
// ====== FEATURE 5: HAR Exporter ======
|
|
428
|
+
case 'export_har': {
|
|
429
|
+
// ponytail: minimal HAR 1.2 mapping without dependencies
|
|
430
|
+
const har = {
|
|
431
|
+
log: {
|
|
432
|
+
version: '1.2',
|
|
433
|
+
creator: { name: 'Real Browser MCP', version: '1.0' },
|
|
434
|
+
entries: state_1.state.networkRecords.filter((r) => r.type === 'response').map((r) => ({
|
|
435
|
+
startedDateTime: new Date(r.timestamp).toISOString(),
|
|
436
|
+
request: {
|
|
437
|
+
method: r.method || 'GET',
|
|
438
|
+
url: r.url,
|
|
439
|
+
headers: Object.entries(r.headers || {}).map(([name, value]) => ({ name, value: String(value) })),
|
|
440
|
+
postData: r.requestBody ? { text: r.requestBody } : undefined
|
|
441
|
+
},
|
|
442
|
+
response: {
|
|
443
|
+
status: r.status || 200,
|
|
444
|
+
content: {
|
|
445
|
+
mimeType: r.contentType || 'text/plain',
|
|
446
|
+
text: r.responseBody || ''
|
|
447
|
+
}
|
|
448
|
+
},
|
|
449
|
+
time: 0
|
|
450
|
+
}))
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
return { success: true, count: har.log.entries.length, har };
|
|
454
|
+
}
|
|
404
455
|
}
|
|
405
456
|
let records = state_1.state.networkRecords;
|
|
406
457
|
if (filter.resourceType) {
|
|
@@ -418,54 +469,6 @@ exports.networkHandlers = {
|
|
|
418
469
|
}
|
|
419
470
|
return { success: true, recording: state_1.state.isRecordingNetwork, count: records.length, records: records.slice(-200) };
|
|
420
471
|
},
|
|
421
|
-
async cookie_manager(params = {}) {
|
|
422
|
-
const { page } = (0, state_1.requireBrowser)();
|
|
423
|
-
const { action = 'get', name, value, domain, expires } = params;
|
|
424
|
-
(0, state_1.notifyProgress)('cookie_manager', 'started', `Cookie action: ${action}`);
|
|
425
|
-
// Playwright/Patchright: cookies are managed via the BrowserContext, not the page
|
|
426
|
-
const context = page.context();
|
|
427
|
-
switch (action) {
|
|
428
|
-
case 'get': {
|
|
429
|
-
const cookies = await context.cookies();
|
|
430
|
-
(0, state_1.notifyProgress)('cookie_manager', 'completed', `Retrieved ${cookies.length} cookies`);
|
|
431
|
-
return { success: true, cookies: name ? cookies.filter(c => c.name === name) : cookies };
|
|
432
|
-
}
|
|
433
|
-
case 'set': {
|
|
434
|
-
await context.addCookies([{
|
|
435
|
-
name,
|
|
436
|
-
value,
|
|
437
|
-
domain: domain || new URL(page.url()).hostname,
|
|
438
|
-
path: '/',
|
|
439
|
-
...(expires ? { expires } : {})
|
|
440
|
-
}]);
|
|
441
|
-
(0, state_1.notifyProgress)('cookie_manager', 'completed', `Cookie set: ${name}`);
|
|
442
|
-
return { success: true, message: `Cookie ${name} set` };
|
|
443
|
-
}
|
|
444
|
-
case 'delete': {
|
|
445
|
-
// Playwright has no per-cookie delete: clear all, then re-add the ones we keep
|
|
446
|
-
const toDelete = await context.cookies();
|
|
447
|
-
const remaining = name ? toDelete.filter(c => c.name !== name) : [];
|
|
448
|
-
const removedCount = toDelete.length - remaining.length;
|
|
449
|
-
await context.clearCookies();
|
|
450
|
-
if (remaining.length) {
|
|
451
|
-
await context.addCookies(remaining.map(c => ({
|
|
452
|
-
name: c.name, value: c.value, domain: c.domain, path: c.path,
|
|
453
|
-
...(c.expires && c.expires > 0 ? { expires: c.expires } : {}),
|
|
454
|
-
httpOnly: c.httpOnly, secure: c.secure, sameSite: c.sameSite
|
|
455
|
-
})));
|
|
456
|
-
}
|
|
457
|
-
(0, state_1.notifyProgress)('cookie_manager', 'completed', `Deleted ${removedCount} cookie(s)`);
|
|
458
|
-
return { success: true, message: `Deleted ${removedCount} cookie(s)` };
|
|
459
|
-
}
|
|
460
|
-
case 'clear': {
|
|
461
|
-
const allCookies = await context.cookies();
|
|
462
|
-
await context.clearCookies();
|
|
463
|
-
(0, state_1.notifyProgress)('cookie_manager', 'completed', `Cleared ${allCookies.length} cookies`);
|
|
464
|
-
return { success: true, message: `Cleared ${allCookies.length} cookies` };
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
return { success: false, error: 'Invalid action' };
|
|
468
|
-
},
|
|
469
472
|
async extract_data(params = {}) {
|
|
470
473
|
const { page } = (0, state_1.requireBrowser)();
|
|
471
474
|
const { type = 'auto', pattern, selector, jsonPath, source = 'all', autoDecode = true, flags = 'gi', types = ['all'], includeTitle = true, includeCanonical = true, maxMatches = 100, maxJsonObjects = 50, waitForSelector = false, selectorTimeout = 10000 } = params;
|
|
@@ -699,8 +702,112 @@ exports.networkHandlers = {
|
|
|
699
702
|
}
|
|
700
703
|
return autoResults;
|
|
701
704
|
};
|
|
705
|
+
// Helper: Extract Links (merged from link_harvester)
|
|
706
|
+
const extractLinks = async () => {
|
|
707
|
+
const { includeHidden = true, searchIframes = false } = params;
|
|
708
|
+
const doExtract = async (context) => {
|
|
709
|
+
return await context.evaluate(({ incHidden }) => {
|
|
710
|
+
const allLinks = [];
|
|
711
|
+
const seenUrls = new Set();
|
|
712
|
+
const addLink = (href, text, source, element) => {
|
|
713
|
+
if (!href || seenUrls.has(href))
|
|
714
|
+
return;
|
|
715
|
+
if (!href.startsWith('http') && !href.startsWith('//'))
|
|
716
|
+
return;
|
|
717
|
+
if (href.startsWith('//'))
|
|
718
|
+
href = window.location.protocol + href;
|
|
719
|
+
seenUrls.add(href);
|
|
720
|
+
allLinks.push({
|
|
721
|
+
href,
|
|
722
|
+
text: (text || '').trim().substring(0, 100),
|
|
723
|
+
source,
|
|
724
|
+
hidden: element ? (element.offsetParent === null || getComputedStyle(element).display === 'none' || getComputedStyle(element).visibility === 'hidden') : false
|
|
725
|
+
});
|
|
726
|
+
};
|
|
727
|
+
document.querySelectorAll('a[href]').forEach(a => addLink(a.href, a.textContent, 'anchor', a));
|
|
728
|
+
const dataAttrs = ['data-href', 'data-url', 'data-link', 'data-src', 'data-file', 'data-download'];
|
|
729
|
+
dataAttrs.forEach(attr => document.querySelectorAll(`[${attr}]`).forEach(el => addLink(el.getAttribute(attr), el.textContent, `${attr}`, el)));
|
|
730
|
+
if (incHidden) {
|
|
731
|
+
document.querySelectorAll('[onclick]').forEach(el => {
|
|
732
|
+
const onclick = el.getAttribute('onclick');
|
|
733
|
+
if (!onclick)
|
|
734
|
+
return;
|
|
735
|
+
const urlMatches = onclick.match(/https?:\/\/[^\s"'<>]+/gi) || [];
|
|
736
|
+
urlMatches.forEach(url => addLink(url, el.textContent, 'onclick', el));
|
|
737
|
+
const hrefMatch = onclick.match(/location\.href\s*=\s*['"]([^'"]+)['"]/);
|
|
738
|
+
if (hrefMatch)
|
|
739
|
+
addLink(hrefMatch[1], el.textContent, 'onclick-location', el);
|
|
740
|
+
const openMatch = onclick.match(/window\.open\s*\(\s*['"]([^'"]+)['"]/);
|
|
741
|
+
if (openMatch)
|
|
742
|
+
addLink(openMatch[1], el.textContent, 'onclick-window-open', el);
|
|
743
|
+
});
|
|
744
|
+
const scripts = [...document.querySelectorAll('script')].slice(0, 20);
|
|
745
|
+
scripts.forEach(script => {
|
|
746
|
+
const content = script.textContent || '';
|
|
747
|
+
const patterns = [
|
|
748
|
+
/["']?(https?:\/\/[^"'\s<>]+\.(mp4|mkv|avi|m3u8|mpd|zip|rar|pdf))[^"'\s<>]*["']?/gi,
|
|
749
|
+
/download[_-]?url\s*[:=]\s*["']([^"']+)["']/gi,
|
|
750
|
+
/file\s*[:=]\s*["']([^"']+)["']/gi
|
|
751
|
+
];
|
|
752
|
+
patterns.forEach(pattern => {
|
|
753
|
+
let match;
|
|
754
|
+
while ((match = pattern.exec(content)) !== null)
|
|
755
|
+
addLink(match[1], 'script-extracted', 'script', null);
|
|
756
|
+
});
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
document.querySelectorAll('a[href^="javascript:"]').forEach(a => {
|
|
760
|
+
const match = a.getAttribute('href')?.match(/https?:\/\/[^\s"'<>]+/gi);
|
|
761
|
+
if (match)
|
|
762
|
+
match.forEach(url => addLink(url, a.textContent, 'javascript-href', a));
|
|
763
|
+
});
|
|
764
|
+
document.querySelectorAll('input[type="hidden"]').forEach((input) => {
|
|
765
|
+
if (input.value && (input.value.startsWith('http') || input.value.startsWith('//')))
|
|
766
|
+
addLink(input.value, input.name || input.id, 'hidden-input', input);
|
|
767
|
+
});
|
|
768
|
+
const metaRefresh = document.querySelector('meta[http-equiv="refresh"]');
|
|
769
|
+
if (metaRefresh) {
|
|
770
|
+
const match = metaRefresh.getAttribute('content')?.match(/url=(.+)/i);
|
|
771
|
+
if (match)
|
|
772
|
+
addLink(match[1].trim().replace(/['"]/g, ''), 'meta-refresh', 'meta', null);
|
|
773
|
+
}
|
|
774
|
+
document.querySelectorAll('iframe[src]').forEach((iframe) => addLink(iframe.src, 'iframe', 'iframe', iframe));
|
|
775
|
+
return allLinks;
|
|
776
|
+
}, { incHidden: includeHidden }).catch(() => []);
|
|
777
|
+
};
|
|
778
|
+
let links = await doExtract(page);
|
|
779
|
+
if (searchIframes) {
|
|
780
|
+
const frames = page.frames();
|
|
781
|
+
for (let i = 1; i < frames.length && i < 5; i++) {
|
|
782
|
+
try {
|
|
783
|
+
const frame = frames[i];
|
|
784
|
+
if (frame.url() && frame.url() !== 'about:blank') {
|
|
785
|
+
const frameLinks = await doExtract(frame);
|
|
786
|
+
frameLinks.forEach((link) => link.source = `iframe:${link.source}`);
|
|
787
|
+
links = [...links, ...frameLinks];
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
catch (e) { }
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
if (!includeHidden)
|
|
794
|
+
links = links.filter((link) => !link.hidden);
|
|
795
|
+
const seen = new Set();
|
|
796
|
+
return links.filter((link) => {
|
|
797
|
+
if (seen.has(link.href))
|
|
798
|
+
return false;
|
|
799
|
+
seen.add(link.href);
|
|
800
|
+
return true;
|
|
801
|
+
});
|
|
802
|
+
};
|
|
702
803
|
// Main switch based on type
|
|
703
804
|
switch (type) {
|
|
805
|
+
case 'links': {
|
|
806
|
+
const links = await extractLinks();
|
|
807
|
+
results.extracted = { count: links.length, links };
|
|
808
|
+
(0, state_1.notifyProgress)('extract_data', 'completed', `Links: ${links.length} extracted`);
|
|
809
|
+
break;
|
|
810
|
+
}
|
|
704
811
|
case 'regex': {
|
|
705
812
|
if (!pattern) {
|
|
706
813
|
return { success: false, error: 'Pattern is required for regex extraction' };
|
|
@@ -728,7 +835,7 @@ exports.networkHandlers = {
|
|
|
728
835
|
}
|
|
729
836
|
case 'structured': {
|
|
730
837
|
if (!selector) {
|
|
731
|
-
return { success: false, error: 'Selector is required for structured extraction' };
|
|
838
|
+
return { success: false, error: 'Selector is required for structured extraction. 💡 AI HINT: Run see_page(annotate: true) first to discover valid selectors or annotation IDs.' };
|
|
732
839
|
}
|
|
733
840
|
results.extracted = await extractStructured(selector, waitForSelector, selectorTimeout);
|
|
734
841
|
if (results.extracted.error) {
|
|
@@ -1143,6 +1250,28 @@ exports.networkHandlers = {
|
|
|
1143
1250
|
return { success: false, error: `Unknown type: ${type}. Supported: regex, json, meta, structured, auto, deobfuscate, apiDiscovery, decrypt` };
|
|
1144
1251
|
}
|
|
1145
1252
|
return results;
|
|
1253
|
+
},
|
|
1254
|
+
async replay_request(params) {
|
|
1255
|
+
const { page } = (0, state_1.requireBrowser)();
|
|
1256
|
+
const { url, method = 'GET', headers, body } = params;
|
|
1257
|
+
(0, state_1.notifyProgress)('replay_request', 'started', `Replaying ${method} to ${url}`);
|
|
1258
|
+
// ponytail: reuse page.evaluate to fire native fetch, bypasses CORS & uses exact browser context auth/cookies
|
|
1259
|
+
try {
|
|
1260
|
+
const result = await page.evaluate(async ({ u, m, h, b }) => {
|
|
1261
|
+
const res = await fetch(u, { method: m, headers: h, body: b });
|
|
1262
|
+
return {
|
|
1263
|
+
status: res.status,
|
|
1264
|
+
headers: Object.fromEntries(res.headers.entries()),
|
|
1265
|
+
body: await res.text().catch(() => null)
|
|
1266
|
+
};
|
|
1267
|
+
}, { u: url, m: method, h: headers || {}, b: body });
|
|
1268
|
+
(0, state_1.notifyProgress)('replay_request', 'completed', `Replay finished with status ${result.status}`);
|
|
1269
|
+
return { success: true, result };
|
|
1270
|
+
}
|
|
1271
|
+
catch (e) {
|
|
1272
|
+
(0, state_1.notifyProgress)('replay_request', 'error', `Replay failed: ${e.message}`);
|
|
1273
|
+
return { success: false, error: e.message };
|
|
1274
|
+
}
|
|
1146
1275
|
}
|
|
1147
1276
|
};
|
|
1148
1277
|
//# sourceMappingURL=network.js.map
|