@reconcrap/boss-recommend-mcp 2.0.46 → 2.0.47
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/bin/boss-recommend-mcp.js +4 -4
- package/config/screening-config.example.json +27 -27
- package/package.json +1 -1
- package/scripts/postinstall.cjs +44 -44
- package/skills/boss-chat/README.md +39 -39
- package/skills/boss-chat/SKILL.md +93 -93
- package/skills/boss-recommend-pipeline/README.md +12 -12
- package/skills/boss-recommend-pipeline/SKILL.md +180 -180
- package/skills/boss-recruit-pipeline/README.md +17 -17
- package/skills/boss-recruit-pipeline/SKILL.md +58 -58
- package/src/chat-mcp.js +1780 -1780
- package/src/chat-runtime-config.js +749 -749
- package/src/cli.js +3054 -3054
- package/src/core/boss-cards/index.js +199 -199
- package/src/core/browser/index.js +1453 -1453
- package/src/core/capture/index.js +1201 -1201
- package/src/core/cv-acquisition/index.js +238 -238
- package/src/core/cv-capture-target/index.js +299 -299
- package/src/core/greet-quota/index.js +54 -54
- package/src/core/infinite-list/index.js +1326 -1326
- package/src/core/reporting/legacy-csv.js +341 -341
- package/src/core/run/timing.js +33 -33
- package/src/core/screening/index.js +50 -3
- package/src/core/self-heal/index.js +973 -973
- package/src/core/self-heal/viewport.js +564 -564
- package/src/domains/chat/cards.js +137 -137
- package/src/domains/chat/constants.js +221 -221
- package/src/domains/chat/detail.js +1668 -1668
- package/src/domains/chat/index.js +7 -7
- package/src/domains/chat/jobs.js +592 -592
- package/src/domains/chat/page-guard.js +98 -98
- package/src/domains/chat/roots.js +56 -56
- package/src/domains/chat/run-service.js +1977 -1977
- package/src/domains/recommend/actions.js +457 -457
- package/src/domains/recommend/cards.js +243 -243
- package/src/domains/recommend/constants.js +165 -165
- package/src/domains/recommend/detail.js +25 -18
- package/src/domains/recommend/filters.js +610 -610
- package/src/domains/recommend/index.js +10 -10
- package/src/domains/recommend/jobs.js +316 -316
- package/src/domains/recommend/refresh.js +472 -472
- package/src/domains/recommend/roots.js +80 -80
- package/src/domains/recommend/run-service.js +27 -20
- package/src/domains/recommend/scopes.js +246 -246
- package/src/domains/recruit/actions.js +277 -277
- package/src/domains/recruit/cards.js +74 -74
- package/src/domains/recruit/constants.js +167 -167
- package/src/domains/recruit/detail.js +461 -461
- package/src/domains/recruit/index.js +9 -9
- package/src/domains/recruit/instruction-parser.js +451 -451
- package/src/domains/recruit/refresh.js +44 -44
- package/src/domains/recruit/roots.js +68 -68
- package/src/domains/recruit/run-service.js +1207 -1207
- package/src/domains/recruit/search.js +1202 -1202
- package/src/recommend-mcp.js +22 -22
- package/src/recruit-mcp.js +1338 -1338
|
@@ -1,299 +1,299 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getFrameDocumentNodeId,
|
|
3
|
-
getNodeBox,
|
|
4
|
-
querySelector,
|
|
5
|
-
querySelectorAll,
|
|
6
|
-
sleep
|
|
7
|
-
} from "../browser/index.js";
|
|
8
|
-
|
|
9
|
-
export const CV_CAPTURE_TARGET_SELECTORS = Object.freeze([
|
|
10
|
-
".resume-center-side .resume-detail-wrap",
|
|
11
|
-
".resume-container .resume-detail-wrap",
|
|
12
|
-
".resume-container .resume-content-wrap",
|
|
13
|
-
".resume-item-detail",
|
|
14
|
-
".resume-detail-wrap",
|
|
15
|
-
".resume-content-wrap",
|
|
16
|
-
".resume-common-wrap",
|
|
17
|
-
".new-resume-online-main-ui",
|
|
18
|
-
".resume-detail",
|
|
19
|
-
".resume-recommend",
|
|
20
|
-
"canvas#resume",
|
|
21
|
-
".resume-container"
|
|
22
|
-
]);
|
|
23
|
-
|
|
24
|
-
const IFRAME_BODY_SELECTORS = Object.freeze(["body", "html"]);
|
|
25
|
-
|
|
26
|
-
function slotNodeId(slot = null) {
|
|
27
|
-
return Number(slot?.node_id || slot?.nodeId || 0) || 0;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function rootNodeId(root = null) {
|
|
31
|
-
return Number(root?.nodeId || root?.node_id || root?.root_node_id || 0) || 0;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function normalizeRootName(root = null, fallback = "") {
|
|
35
|
-
return String(root?.name || root?.root || fallback || "").trim() || null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function uniqueRoots(roots = []) {
|
|
39
|
-
const seen = new Set();
|
|
40
|
-
const result = [];
|
|
41
|
-
for (const root of roots) {
|
|
42
|
-
const nodeId = rootNodeId(root);
|
|
43
|
-
if (!nodeId || seen.has(nodeId)) continue;
|
|
44
|
-
seen.add(nodeId);
|
|
45
|
-
result.push({
|
|
46
|
-
...root,
|
|
47
|
-
name: normalizeRootName(root),
|
|
48
|
-
nodeId
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
return result;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function slotAsRoot(slot = null, fallbackName = "") {
|
|
55
|
-
const nodeId = slotNodeId(slot);
|
|
56
|
-
if (!nodeId) return null;
|
|
57
|
-
return {
|
|
58
|
-
name: normalizeRootName(slot, fallbackName),
|
|
59
|
-
nodeId,
|
|
60
|
-
selector: slot?.selector || null,
|
|
61
|
-
root_node_id: slot?.root_node_id || null
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function isVisibleBox(box = null) {
|
|
66
|
-
return box?.rect?.width > 2 && box?.rect?.height > 2;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
async function readVisibleBox(client, nodeId) {
|
|
70
|
-
if (!nodeId) return null;
|
|
71
|
-
try {
|
|
72
|
-
const box = await getNodeBox(client, nodeId);
|
|
73
|
-
return isVisibleBox(box) ? box : null;
|
|
74
|
-
} catch {
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function isCvScopedSelector(selector = "") {
|
|
80
|
-
const normalized = String(selector || "").trim();
|
|
81
|
-
if (!normalized) return false;
|
|
82
|
-
if (/boss-popup|boss-dialog|dialog-wrap|geek-detail-modal|\bmodal\b|new-chat-resume-dialog-main-ui/i.test(normalized)) {
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
return /resume-item-detail|resume-detail-wrap|resume-content-wrap|resume-common-wrap|new-resume-online-main-ui|resume-detail(?:\b|[.#:])|resume-recommend|canvas#resume|resume-container/i.test(normalized);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function buildTarget({
|
|
89
|
-
domain = "",
|
|
90
|
-
nodeId,
|
|
91
|
-
source,
|
|
92
|
-
selector = null,
|
|
93
|
-
root = null,
|
|
94
|
-
rootNodeId = null,
|
|
95
|
-
box = null,
|
|
96
|
-
iframeNodeId = null,
|
|
97
|
-
iframeDocumentNodeId = null,
|
|
98
|
-
fallback = false
|
|
99
|
-
} = {}) {
|
|
100
|
-
return {
|
|
101
|
-
schema_version: 1,
|
|
102
|
-
domain: domain || null,
|
|
103
|
-
node_id: nodeId,
|
|
104
|
-
source,
|
|
105
|
-
selector,
|
|
106
|
-
root,
|
|
107
|
-
root_node_id: rootNodeId || null,
|
|
108
|
-
iframe_node_id: iframeNodeId || null,
|
|
109
|
-
iframe_document_node_id: iframeDocumentNodeId || null,
|
|
110
|
-
cv_only: !fallback,
|
|
111
|
-
fallback: Boolean(fallback),
|
|
112
|
-
rect: box?.rect || null,
|
|
113
|
-
center: box?.center || null
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async function firstVisibleSelectorTarget(client, roots = [], selectors = CV_CAPTURE_TARGET_SELECTORS, {
|
|
118
|
-
domain = "",
|
|
119
|
-
source = "cv_selector",
|
|
120
|
-
iframeNodeId = null,
|
|
121
|
-
iframeDocumentNodeId = null
|
|
122
|
-
} = {}) {
|
|
123
|
-
for (const root of uniqueRoots(roots)) {
|
|
124
|
-
for (const selector of selectors) {
|
|
125
|
-
let nodeIds = [];
|
|
126
|
-
try {
|
|
127
|
-
nodeIds = await querySelectorAll(client, root.nodeId, selector);
|
|
128
|
-
} catch {
|
|
129
|
-
nodeIds = [];
|
|
130
|
-
}
|
|
131
|
-
for (const nodeId of nodeIds) {
|
|
132
|
-
const box = await readVisibleBox(client, nodeId);
|
|
133
|
-
if (!box) continue;
|
|
134
|
-
return buildTarget({
|
|
135
|
-
domain,
|
|
136
|
-
nodeId,
|
|
137
|
-
source,
|
|
138
|
-
selector,
|
|
139
|
-
root: root.name,
|
|
140
|
-
rootNodeId: root.nodeId,
|
|
141
|
-
box,
|
|
142
|
-
iframeNodeId,
|
|
143
|
-
iframeDocumentNodeId
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return null;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
async function visibleSlotTarget(client, slot = null, {
|
|
152
|
-
domain = "",
|
|
153
|
-
source = "cv_slot",
|
|
154
|
-
fallback = false
|
|
155
|
-
} = {}) {
|
|
156
|
-
const nodeId = slotNodeId(slot);
|
|
157
|
-
if (!nodeId) return null;
|
|
158
|
-
if (!fallback && !isCvScopedSelector(slot?.selector)) return null;
|
|
159
|
-
const box = await readVisibleBox(client, nodeId);
|
|
160
|
-
if (!box) return null;
|
|
161
|
-
return buildTarget({
|
|
162
|
-
domain,
|
|
163
|
-
nodeId,
|
|
164
|
-
source,
|
|
165
|
-
selector: slot?.selector || null,
|
|
166
|
-
root: slot?.root || null,
|
|
167
|
-
rootNodeId: slot?.root_node_id || null,
|
|
168
|
-
box,
|
|
169
|
-
fallback
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
async function resolveIframeCaptureTarget(client, resumeIframe = null, {
|
|
174
|
-
domain = "",
|
|
175
|
-
selectors = CV_CAPTURE_TARGET_SELECTORS
|
|
176
|
-
} = {}) {
|
|
177
|
-
const iframeNodeId = slotNodeId(resumeIframe);
|
|
178
|
-
if (!iframeNodeId) return null;
|
|
179
|
-
|
|
180
|
-
try {
|
|
181
|
-
const documentNodeId = await getFrameDocumentNodeId(client, iframeNodeId);
|
|
182
|
-
const selectorTarget = await firstVisibleSelectorTarget(client, [{
|
|
183
|
-
name: "resume-iframe-document",
|
|
184
|
-
nodeId: documentNodeId
|
|
185
|
-
}], selectors, {
|
|
186
|
-
domain,
|
|
187
|
-
source: "resume_iframe_cv_selector",
|
|
188
|
-
iframeNodeId,
|
|
189
|
-
iframeDocumentNodeId: documentNodeId
|
|
190
|
-
});
|
|
191
|
-
if (selectorTarget) return selectorTarget;
|
|
192
|
-
|
|
193
|
-
for (const selector of IFRAME_BODY_SELECTORS) {
|
|
194
|
-
const nodeId = await querySelector(client, documentNodeId, selector).catch(() => 0);
|
|
195
|
-
const box = await readVisibleBox(client, nodeId);
|
|
196
|
-
if (!box) continue;
|
|
197
|
-
return buildTarget({
|
|
198
|
-
domain,
|
|
199
|
-
nodeId,
|
|
200
|
-
source: "resume_iframe_body",
|
|
201
|
-
selector,
|
|
202
|
-
root: "resume-iframe-document",
|
|
203
|
-
rootNodeId: documentNodeId,
|
|
204
|
-
box,
|
|
205
|
-
iframeNodeId,
|
|
206
|
-
iframeDocumentNodeId: documentNodeId
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
} catch {}
|
|
210
|
-
|
|
211
|
-
const iframeBox = await readVisibleBox(client, iframeNodeId);
|
|
212
|
-
if (!iframeBox) return null;
|
|
213
|
-
return buildTarget({
|
|
214
|
-
domain,
|
|
215
|
-
nodeId: iframeNodeId,
|
|
216
|
-
source: "resume_iframe_element",
|
|
217
|
-
selector: resumeIframe?.selector || null,
|
|
218
|
-
root: resumeIframe?.root || null,
|
|
219
|
-
rootNodeId: resumeIframe?.root_node_id || null,
|
|
220
|
-
box: iframeBox,
|
|
221
|
-
iframeNodeId,
|
|
222
|
-
fallback: false
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
async function resolveSlotCaptureTarget(client, slot = null, {
|
|
227
|
-
domain = "",
|
|
228
|
-
slotName = "content",
|
|
229
|
-
selectors = CV_CAPTURE_TARGET_SELECTORS
|
|
230
|
-
} = {}) {
|
|
231
|
-
const root = slotAsRoot(slot, slotName);
|
|
232
|
-
const selectorTarget = root
|
|
233
|
-
? await firstVisibleSelectorTarget(client, [root], selectors, {
|
|
234
|
-
domain,
|
|
235
|
-
source: `${slotName}_cv_selector`
|
|
236
|
-
})
|
|
237
|
-
: null;
|
|
238
|
-
if (selectorTarget) return selectorTarget;
|
|
239
|
-
return visibleSlotTarget(client, slot, {
|
|
240
|
-
domain,
|
|
241
|
-
source: `${slotName}_cv_slot`
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
export async function resolveCvCaptureTarget(client, detailState = null, {
|
|
246
|
-
domain = "",
|
|
247
|
-
selectors = CV_CAPTURE_TARGET_SELECTORS
|
|
248
|
-
} = {}) {
|
|
249
|
-
const iframeTarget = await resolveIframeCaptureTarget(client, detailState?.resumeIframe, {
|
|
250
|
-
domain,
|
|
251
|
-
selectors
|
|
252
|
-
});
|
|
253
|
-
if (iframeTarget) return iframeTarget;
|
|
254
|
-
|
|
255
|
-
const contentTarget = await resolveSlotCaptureTarget(client, detailState?.content, {
|
|
256
|
-
domain,
|
|
257
|
-
slotName: "content",
|
|
258
|
-
selectors
|
|
259
|
-
});
|
|
260
|
-
if (contentTarget) return contentTarget;
|
|
261
|
-
|
|
262
|
-
const popupTarget = await resolveSlotCaptureTarget(client, detailState?.popup, {
|
|
263
|
-
domain,
|
|
264
|
-
slotName: "popup",
|
|
265
|
-
selectors
|
|
266
|
-
});
|
|
267
|
-
if (popupTarget) return popupTarget;
|
|
268
|
-
|
|
269
|
-
return firstVisibleSelectorTarget(client, detailState?.roots || [], selectors, {
|
|
270
|
-
domain,
|
|
271
|
-
source: "root_cv_selector"
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
export async function waitForCvCaptureTarget(client, detailState = null, {
|
|
276
|
-
timeoutMs = 6000,
|
|
277
|
-
intervalMs = 250,
|
|
278
|
-
...options
|
|
279
|
-
} = {}) {
|
|
280
|
-
const started = Date.now();
|
|
281
|
-
let target = null;
|
|
282
|
-
while (Date.now() - started <= Math.max(0, Number(timeoutMs) || 0)) {
|
|
283
|
-
target = await resolveCvCaptureTarget(client, detailState, options);
|
|
284
|
-
if (target?.node_id) {
|
|
285
|
-
return {
|
|
286
|
-
ok: true,
|
|
287
|
-
elapsed_ms: Date.now() - started,
|
|
288
|
-
target
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
await sleep(Math.max(50, Number(intervalMs) || 250));
|
|
292
|
-
}
|
|
293
|
-
target = await resolveCvCaptureTarget(client, detailState, options);
|
|
294
|
-
return {
|
|
295
|
-
ok: Boolean(target?.node_id),
|
|
296
|
-
elapsed_ms: Date.now() - started,
|
|
297
|
-
target: target || null
|
|
298
|
-
};
|
|
299
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
getFrameDocumentNodeId,
|
|
3
|
+
getNodeBox,
|
|
4
|
+
querySelector,
|
|
5
|
+
querySelectorAll,
|
|
6
|
+
sleep
|
|
7
|
+
} from "../browser/index.js";
|
|
8
|
+
|
|
9
|
+
export const CV_CAPTURE_TARGET_SELECTORS = Object.freeze([
|
|
10
|
+
".resume-center-side .resume-detail-wrap",
|
|
11
|
+
".resume-container .resume-detail-wrap",
|
|
12
|
+
".resume-container .resume-content-wrap",
|
|
13
|
+
".resume-item-detail",
|
|
14
|
+
".resume-detail-wrap",
|
|
15
|
+
".resume-content-wrap",
|
|
16
|
+
".resume-common-wrap",
|
|
17
|
+
".new-resume-online-main-ui",
|
|
18
|
+
".resume-detail",
|
|
19
|
+
".resume-recommend",
|
|
20
|
+
"canvas#resume",
|
|
21
|
+
".resume-container"
|
|
22
|
+
]);
|
|
23
|
+
|
|
24
|
+
const IFRAME_BODY_SELECTORS = Object.freeze(["body", "html"]);
|
|
25
|
+
|
|
26
|
+
function slotNodeId(slot = null) {
|
|
27
|
+
return Number(slot?.node_id || slot?.nodeId || 0) || 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function rootNodeId(root = null) {
|
|
31
|
+
return Number(root?.nodeId || root?.node_id || root?.root_node_id || 0) || 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function normalizeRootName(root = null, fallback = "") {
|
|
35
|
+
return String(root?.name || root?.root || fallback || "").trim() || null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function uniqueRoots(roots = []) {
|
|
39
|
+
const seen = new Set();
|
|
40
|
+
const result = [];
|
|
41
|
+
for (const root of roots) {
|
|
42
|
+
const nodeId = rootNodeId(root);
|
|
43
|
+
if (!nodeId || seen.has(nodeId)) continue;
|
|
44
|
+
seen.add(nodeId);
|
|
45
|
+
result.push({
|
|
46
|
+
...root,
|
|
47
|
+
name: normalizeRootName(root),
|
|
48
|
+
nodeId
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function slotAsRoot(slot = null, fallbackName = "") {
|
|
55
|
+
const nodeId = slotNodeId(slot);
|
|
56
|
+
if (!nodeId) return null;
|
|
57
|
+
return {
|
|
58
|
+
name: normalizeRootName(slot, fallbackName),
|
|
59
|
+
nodeId,
|
|
60
|
+
selector: slot?.selector || null,
|
|
61
|
+
root_node_id: slot?.root_node_id || null
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function isVisibleBox(box = null) {
|
|
66
|
+
return box?.rect?.width > 2 && box?.rect?.height > 2;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function readVisibleBox(client, nodeId) {
|
|
70
|
+
if (!nodeId) return null;
|
|
71
|
+
try {
|
|
72
|
+
const box = await getNodeBox(client, nodeId);
|
|
73
|
+
return isVisibleBox(box) ? box : null;
|
|
74
|
+
} catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function isCvScopedSelector(selector = "") {
|
|
80
|
+
const normalized = String(selector || "").trim();
|
|
81
|
+
if (!normalized) return false;
|
|
82
|
+
if (/boss-popup|boss-dialog|dialog-wrap|geek-detail-modal|\bmodal\b|new-chat-resume-dialog-main-ui/i.test(normalized)) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
return /resume-item-detail|resume-detail-wrap|resume-content-wrap|resume-common-wrap|new-resume-online-main-ui|resume-detail(?:\b|[.#:])|resume-recommend|canvas#resume|resume-container/i.test(normalized);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function buildTarget({
|
|
89
|
+
domain = "",
|
|
90
|
+
nodeId,
|
|
91
|
+
source,
|
|
92
|
+
selector = null,
|
|
93
|
+
root = null,
|
|
94
|
+
rootNodeId = null,
|
|
95
|
+
box = null,
|
|
96
|
+
iframeNodeId = null,
|
|
97
|
+
iframeDocumentNodeId = null,
|
|
98
|
+
fallback = false
|
|
99
|
+
} = {}) {
|
|
100
|
+
return {
|
|
101
|
+
schema_version: 1,
|
|
102
|
+
domain: domain || null,
|
|
103
|
+
node_id: nodeId,
|
|
104
|
+
source,
|
|
105
|
+
selector,
|
|
106
|
+
root,
|
|
107
|
+
root_node_id: rootNodeId || null,
|
|
108
|
+
iframe_node_id: iframeNodeId || null,
|
|
109
|
+
iframe_document_node_id: iframeDocumentNodeId || null,
|
|
110
|
+
cv_only: !fallback,
|
|
111
|
+
fallback: Boolean(fallback),
|
|
112
|
+
rect: box?.rect || null,
|
|
113
|
+
center: box?.center || null
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function firstVisibleSelectorTarget(client, roots = [], selectors = CV_CAPTURE_TARGET_SELECTORS, {
|
|
118
|
+
domain = "",
|
|
119
|
+
source = "cv_selector",
|
|
120
|
+
iframeNodeId = null,
|
|
121
|
+
iframeDocumentNodeId = null
|
|
122
|
+
} = {}) {
|
|
123
|
+
for (const root of uniqueRoots(roots)) {
|
|
124
|
+
for (const selector of selectors) {
|
|
125
|
+
let nodeIds = [];
|
|
126
|
+
try {
|
|
127
|
+
nodeIds = await querySelectorAll(client, root.nodeId, selector);
|
|
128
|
+
} catch {
|
|
129
|
+
nodeIds = [];
|
|
130
|
+
}
|
|
131
|
+
for (const nodeId of nodeIds) {
|
|
132
|
+
const box = await readVisibleBox(client, nodeId);
|
|
133
|
+
if (!box) continue;
|
|
134
|
+
return buildTarget({
|
|
135
|
+
domain,
|
|
136
|
+
nodeId,
|
|
137
|
+
source,
|
|
138
|
+
selector,
|
|
139
|
+
root: root.name,
|
|
140
|
+
rootNodeId: root.nodeId,
|
|
141
|
+
box,
|
|
142
|
+
iframeNodeId,
|
|
143
|
+
iframeDocumentNodeId
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function visibleSlotTarget(client, slot = null, {
|
|
152
|
+
domain = "",
|
|
153
|
+
source = "cv_slot",
|
|
154
|
+
fallback = false
|
|
155
|
+
} = {}) {
|
|
156
|
+
const nodeId = slotNodeId(slot);
|
|
157
|
+
if (!nodeId) return null;
|
|
158
|
+
if (!fallback && !isCvScopedSelector(slot?.selector)) return null;
|
|
159
|
+
const box = await readVisibleBox(client, nodeId);
|
|
160
|
+
if (!box) return null;
|
|
161
|
+
return buildTarget({
|
|
162
|
+
domain,
|
|
163
|
+
nodeId,
|
|
164
|
+
source,
|
|
165
|
+
selector: slot?.selector || null,
|
|
166
|
+
root: slot?.root || null,
|
|
167
|
+
rootNodeId: slot?.root_node_id || null,
|
|
168
|
+
box,
|
|
169
|
+
fallback
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async function resolveIframeCaptureTarget(client, resumeIframe = null, {
|
|
174
|
+
domain = "",
|
|
175
|
+
selectors = CV_CAPTURE_TARGET_SELECTORS
|
|
176
|
+
} = {}) {
|
|
177
|
+
const iframeNodeId = slotNodeId(resumeIframe);
|
|
178
|
+
if (!iframeNodeId) return null;
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
const documentNodeId = await getFrameDocumentNodeId(client, iframeNodeId);
|
|
182
|
+
const selectorTarget = await firstVisibleSelectorTarget(client, [{
|
|
183
|
+
name: "resume-iframe-document",
|
|
184
|
+
nodeId: documentNodeId
|
|
185
|
+
}], selectors, {
|
|
186
|
+
domain,
|
|
187
|
+
source: "resume_iframe_cv_selector",
|
|
188
|
+
iframeNodeId,
|
|
189
|
+
iframeDocumentNodeId: documentNodeId
|
|
190
|
+
});
|
|
191
|
+
if (selectorTarget) return selectorTarget;
|
|
192
|
+
|
|
193
|
+
for (const selector of IFRAME_BODY_SELECTORS) {
|
|
194
|
+
const nodeId = await querySelector(client, documentNodeId, selector).catch(() => 0);
|
|
195
|
+
const box = await readVisibleBox(client, nodeId);
|
|
196
|
+
if (!box) continue;
|
|
197
|
+
return buildTarget({
|
|
198
|
+
domain,
|
|
199
|
+
nodeId,
|
|
200
|
+
source: "resume_iframe_body",
|
|
201
|
+
selector,
|
|
202
|
+
root: "resume-iframe-document",
|
|
203
|
+
rootNodeId: documentNodeId,
|
|
204
|
+
box,
|
|
205
|
+
iframeNodeId,
|
|
206
|
+
iframeDocumentNodeId: documentNodeId
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
} catch {}
|
|
210
|
+
|
|
211
|
+
const iframeBox = await readVisibleBox(client, iframeNodeId);
|
|
212
|
+
if (!iframeBox) return null;
|
|
213
|
+
return buildTarget({
|
|
214
|
+
domain,
|
|
215
|
+
nodeId: iframeNodeId,
|
|
216
|
+
source: "resume_iframe_element",
|
|
217
|
+
selector: resumeIframe?.selector || null,
|
|
218
|
+
root: resumeIframe?.root || null,
|
|
219
|
+
rootNodeId: resumeIframe?.root_node_id || null,
|
|
220
|
+
box: iframeBox,
|
|
221
|
+
iframeNodeId,
|
|
222
|
+
fallback: false
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async function resolveSlotCaptureTarget(client, slot = null, {
|
|
227
|
+
domain = "",
|
|
228
|
+
slotName = "content",
|
|
229
|
+
selectors = CV_CAPTURE_TARGET_SELECTORS
|
|
230
|
+
} = {}) {
|
|
231
|
+
const root = slotAsRoot(slot, slotName);
|
|
232
|
+
const selectorTarget = root
|
|
233
|
+
? await firstVisibleSelectorTarget(client, [root], selectors, {
|
|
234
|
+
domain,
|
|
235
|
+
source: `${slotName}_cv_selector`
|
|
236
|
+
})
|
|
237
|
+
: null;
|
|
238
|
+
if (selectorTarget) return selectorTarget;
|
|
239
|
+
return visibleSlotTarget(client, slot, {
|
|
240
|
+
domain,
|
|
241
|
+
source: `${slotName}_cv_slot`
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export async function resolveCvCaptureTarget(client, detailState = null, {
|
|
246
|
+
domain = "",
|
|
247
|
+
selectors = CV_CAPTURE_TARGET_SELECTORS
|
|
248
|
+
} = {}) {
|
|
249
|
+
const iframeTarget = await resolveIframeCaptureTarget(client, detailState?.resumeIframe, {
|
|
250
|
+
domain,
|
|
251
|
+
selectors
|
|
252
|
+
});
|
|
253
|
+
if (iframeTarget) return iframeTarget;
|
|
254
|
+
|
|
255
|
+
const contentTarget = await resolveSlotCaptureTarget(client, detailState?.content, {
|
|
256
|
+
domain,
|
|
257
|
+
slotName: "content",
|
|
258
|
+
selectors
|
|
259
|
+
});
|
|
260
|
+
if (contentTarget) return contentTarget;
|
|
261
|
+
|
|
262
|
+
const popupTarget = await resolveSlotCaptureTarget(client, detailState?.popup, {
|
|
263
|
+
domain,
|
|
264
|
+
slotName: "popup",
|
|
265
|
+
selectors
|
|
266
|
+
});
|
|
267
|
+
if (popupTarget) return popupTarget;
|
|
268
|
+
|
|
269
|
+
return firstVisibleSelectorTarget(client, detailState?.roots || [], selectors, {
|
|
270
|
+
domain,
|
|
271
|
+
source: "root_cv_selector"
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export async function waitForCvCaptureTarget(client, detailState = null, {
|
|
276
|
+
timeoutMs = 6000,
|
|
277
|
+
intervalMs = 250,
|
|
278
|
+
...options
|
|
279
|
+
} = {}) {
|
|
280
|
+
const started = Date.now();
|
|
281
|
+
let target = null;
|
|
282
|
+
while (Date.now() - started <= Math.max(0, Number(timeoutMs) || 0)) {
|
|
283
|
+
target = await resolveCvCaptureTarget(client, detailState, options);
|
|
284
|
+
if (target?.node_id) {
|
|
285
|
+
return {
|
|
286
|
+
ok: true,
|
|
287
|
+
elapsed_ms: Date.now() - started,
|
|
288
|
+
target
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
await sleep(Math.max(50, Number(intervalMs) || 250));
|
|
292
|
+
}
|
|
293
|
+
target = await resolveCvCaptureTarget(client, detailState, options);
|
|
294
|
+
return {
|
|
295
|
+
ok: Boolean(target?.node_id),
|
|
296
|
+
elapsed_ms: Date.now() - started,
|
|
297
|
+
target: target || null
|
|
298
|
+
};
|
|
299
|
+
}
|