@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,165 +1,165 @@
|
|
|
1
|
-
export const RECOMMEND_TARGET_URL = "https://www.zhipin.com/web/chat/recommend";
|
|
2
|
-
|
|
3
|
-
export const RECOMMEND_PAGE_SCOPE_DEFAULT = "recommend";
|
|
4
|
-
|
|
5
|
-
export const RECOMMEND_PAGE_SCOPE_STATUS = Object.freeze({
|
|
6
|
-
recommend: "0",
|
|
7
|
-
latest: "1",
|
|
8
|
-
featured: "3"
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
export const RECOMMEND_PAGE_SCOPE_LABELS = Object.freeze({
|
|
12
|
-
recommend: "推荐",
|
|
13
|
-
latest: "最新",
|
|
14
|
-
featured: "精选"
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
export const RECOMMEND_IFRAME_SELECTORS = Object.freeze([
|
|
18
|
-
'iframe[name="recommendFrame"]',
|
|
19
|
-
'iframe[src*="/web/frame/recommend/"]',
|
|
20
|
-
"iframe"
|
|
21
|
-
]);
|
|
22
|
-
|
|
23
|
-
export const RECOMMEND_PAGE_SCOPE_TAB_SELECTOR = [
|
|
24
|
-
".tab-list .tab-item[data-status]",
|
|
25
|
-
".tab-wrap .tab-item[data-status]",
|
|
26
|
-
".tab-item[data-status]",
|
|
27
|
-
"[data-status]"
|
|
28
|
-
].join(", ");
|
|
29
|
-
|
|
30
|
-
export const RECOMMEND_FILTER_SELECTORS = Object.freeze({
|
|
31
|
-
trigger: ".filter-label-wrap",
|
|
32
|
-
panel: ".filter-panel",
|
|
33
|
-
groups: Object.freeze({
|
|
34
|
-
recentNotView: ".filter-panel .check-box.recentNotView",
|
|
35
|
-
degree: ".filter-panel .check-box.degree",
|
|
36
|
-
gender: ".filter-panel .check-box.gender",
|
|
37
|
-
school: ".filter-panel .check-box.school"
|
|
38
|
-
}),
|
|
39
|
-
option: ".default.option, .options .option, .option",
|
|
40
|
-
activeOption: ".default.option.active, .options .option.active, .option.active",
|
|
41
|
-
confirmButton: ".filter-panel .btn, .filter-panel button",
|
|
42
|
-
checkBox: ".filter-panel .check-box"
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
export const RECOMMEND_FILTER_GROUP_ORDER = Object.freeze([
|
|
46
|
-
"recentNotView",
|
|
47
|
-
"degree",
|
|
48
|
-
"gender",
|
|
49
|
-
"school"
|
|
50
|
-
]);
|
|
51
|
-
|
|
52
|
-
export const RECOMMEND_RECENT_NOT_VIEW_LABEL = "近14天没有";
|
|
53
|
-
|
|
54
|
-
export const RECOMMEND_CARD_SELECTOR = [
|
|
55
|
-
".candidate-card-wrap .card-inner[data-geek]",
|
|
56
|
-
".candidate-card-wrap [data-geek]",
|
|
57
|
-
"li.geek-info-card a[data-geekid]",
|
|
58
|
-
"a[data-geekid]"
|
|
59
|
-
].join(", ");
|
|
60
|
-
|
|
61
|
-
export const RECOMMEND_LIST_CONTAINER_SELECTORS = Object.freeze([
|
|
62
|
-
".recommend-list",
|
|
63
|
-
".recommend-list-wrap",
|
|
64
|
-
".candidate-list",
|
|
65
|
-
".candidate-card-list",
|
|
66
|
-
".candidate-card-wrap-list",
|
|
67
|
-
".geek-list",
|
|
68
|
-
".geek-list-wrap",
|
|
69
|
-
".card-list",
|
|
70
|
-
".list-wrap",
|
|
71
|
-
".content-list"
|
|
72
|
-
]);
|
|
73
|
-
|
|
74
|
-
export const RECOMMEND_END_REFRESH_SELECTOR = [
|
|
75
|
-
".btn",
|
|
76
|
-
"button",
|
|
77
|
-
'[role="button"]',
|
|
78
|
-
'[class*="refresh"]',
|
|
79
|
-
'[ka*="refresh"]',
|
|
80
|
-
"a"
|
|
81
|
-
].join(", ");
|
|
82
|
-
|
|
83
|
-
export const RECOMMEND_BOTTOM_MARKER_SELECTORS = Object.freeze([
|
|
84
|
-
".finished-wrap",
|
|
85
|
-
".no-data-refresh",
|
|
86
|
-
".load-tips",
|
|
87
|
-
".empty-tip",
|
|
88
|
-
".empty-text",
|
|
89
|
-
".no-data",
|
|
90
|
-
"[class*=\"finished\"]",
|
|
91
|
-
"[class*=\"load-tips\"]"
|
|
92
|
-
]);
|
|
93
|
-
|
|
94
|
-
export const DETAIL_POPUP_SELECTORS = Object.freeze([
|
|
95
|
-
".dialog-wrap.active",
|
|
96
|
-
".boss-popup__wrapper",
|
|
97
|
-
".boss-popup_wrapper",
|
|
98
|
-
".boss-dialog_wrapper",
|
|
99
|
-
".boss-dialog",
|
|
100
|
-
".resume-item-detail",
|
|
101
|
-
".geek-detail-modal",
|
|
102
|
-
'[class*="popup"][class*="wrapper"]',
|
|
103
|
-
'[class*="dialog"][class*="wrapper"]'
|
|
104
|
-
]);
|
|
105
|
-
|
|
106
|
-
export const DETAIL_RESUME_IFRAME_SELECTORS = Object.freeze([
|
|
107
|
-
'iframe[src*="/web/frame/c-resume/"]',
|
|
108
|
-
'iframe[name*="resume"]'
|
|
109
|
-
]);
|
|
110
|
-
|
|
111
|
-
export const DETAIL_CLOSE_SELECTORS = Object.freeze([
|
|
112
|
-
".boss-popup__close",
|
|
113
|
-
".popup-close",
|
|
114
|
-
".modal-close",
|
|
115
|
-
".dialog-close",
|
|
116
|
-
".close-btn",
|
|
117
|
-
'button[aria-label*="关闭"]',
|
|
118
|
-
'button[title*="关闭"]',
|
|
119
|
-
".icon-close",
|
|
120
|
-
'[aria-label*="关闭"]',
|
|
121
|
-
'[title*="关闭"]',
|
|
122
|
-
'[class*="close"]'
|
|
123
|
-
]);
|
|
124
|
-
|
|
125
|
-
export const DETAIL_NETWORK_PATTERNS = Object.freeze([
|
|
126
|
-
/\/wapi\/zpjob\/view\/geek\/info\b/i,
|
|
127
|
-
/\/wapi\/zpitem\/web\/boss\/[^?#]*\/geek\/info\b/i,
|
|
128
|
-
/\/boss\/[^?#]*\/geek\/info\b/i,
|
|
129
|
-
/\/geek\/info\b/i,
|
|
130
|
-
/\/web\/frame\/c-resume\//i,
|
|
131
|
-
/resume/i
|
|
132
|
-
]);
|
|
133
|
-
|
|
134
|
-
export const FAVORITE_BUTTON_SELECTORS = Object.freeze([
|
|
135
|
-
".like-icon-and-text",
|
|
136
|
-
".resume-footer.item-operate [class*=\"collect\"]",
|
|
137
|
-
".resume-footer.item-operate [class*=\"favorite\"]",
|
|
138
|
-
".resume-footer.item-operate [class*=\"like\"]",
|
|
139
|
-
".resume-footer-wrap [class*=\"collect\"]",
|
|
140
|
-
".resume-footer-wrap [class*=\"favorite\"]",
|
|
141
|
-
".resume-footer-wrap [class*=\"like\"]",
|
|
142
|
-
".resume-footer [class*=\"collect\"]",
|
|
143
|
-
".resume-footer [class*=\"favorite\"]",
|
|
144
|
-
".resume-footer [class*=\"like\"]",
|
|
145
|
-
".resume-footer.item-operate button",
|
|
146
|
-
".resume-footer.item-operate .btn",
|
|
147
|
-
".resume-footer.item-operate span",
|
|
148
|
-
".resume-footer-wrap button",
|
|
149
|
-
".resume-footer-wrap .btn",
|
|
150
|
-
".resume-footer-wrap span",
|
|
151
|
-
".resume-footer button",
|
|
152
|
-
".resume-footer .btn",
|
|
153
|
-
".resume-footer span"
|
|
154
|
-
]);
|
|
155
|
-
|
|
156
|
-
export const GREET_BUTTON_RECOMMEND_SELECTORS = Object.freeze([
|
|
157
|
-
"button.btn-v2.btn-sure-v2.btn-greet",
|
|
158
|
-
".resume-footer.item-operate button.btn-v2",
|
|
159
|
-
".resume-footer-wrap button.btn-v2",
|
|
160
|
-
".resume-footer.item-operate button",
|
|
161
|
-
".resume-footer-wrap button",
|
|
162
|
-
".resume-footer button",
|
|
163
|
-
"button[class*=\"greet\"]",
|
|
164
|
-
"button[class*=\"sure\"]"
|
|
165
|
-
]);
|
|
1
|
+
export const RECOMMEND_TARGET_URL = "https://www.zhipin.com/web/chat/recommend";
|
|
2
|
+
|
|
3
|
+
export const RECOMMEND_PAGE_SCOPE_DEFAULT = "recommend";
|
|
4
|
+
|
|
5
|
+
export const RECOMMEND_PAGE_SCOPE_STATUS = Object.freeze({
|
|
6
|
+
recommend: "0",
|
|
7
|
+
latest: "1",
|
|
8
|
+
featured: "3"
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export const RECOMMEND_PAGE_SCOPE_LABELS = Object.freeze({
|
|
12
|
+
recommend: "推荐",
|
|
13
|
+
latest: "最新",
|
|
14
|
+
featured: "精选"
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export const RECOMMEND_IFRAME_SELECTORS = Object.freeze([
|
|
18
|
+
'iframe[name="recommendFrame"]',
|
|
19
|
+
'iframe[src*="/web/frame/recommend/"]',
|
|
20
|
+
"iframe"
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
export const RECOMMEND_PAGE_SCOPE_TAB_SELECTOR = [
|
|
24
|
+
".tab-list .tab-item[data-status]",
|
|
25
|
+
".tab-wrap .tab-item[data-status]",
|
|
26
|
+
".tab-item[data-status]",
|
|
27
|
+
"[data-status]"
|
|
28
|
+
].join(", ");
|
|
29
|
+
|
|
30
|
+
export const RECOMMEND_FILTER_SELECTORS = Object.freeze({
|
|
31
|
+
trigger: ".filter-label-wrap",
|
|
32
|
+
panel: ".filter-panel",
|
|
33
|
+
groups: Object.freeze({
|
|
34
|
+
recentNotView: ".filter-panel .check-box.recentNotView",
|
|
35
|
+
degree: ".filter-panel .check-box.degree",
|
|
36
|
+
gender: ".filter-panel .check-box.gender",
|
|
37
|
+
school: ".filter-panel .check-box.school"
|
|
38
|
+
}),
|
|
39
|
+
option: ".default.option, .options .option, .option",
|
|
40
|
+
activeOption: ".default.option.active, .options .option.active, .option.active",
|
|
41
|
+
confirmButton: ".filter-panel .btn, .filter-panel button",
|
|
42
|
+
checkBox: ".filter-panel .check-box"
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export const RECOMMEND_FILTER_GROUP_ORDER = Object.freeze([
|
|
46
|
+
"recentNotView",
|
|
47
|
+
"degree",
|
|
48
|
+
"gender",
|
|
49
|
+
"school"
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
export const RECOMMEND_RECENT_NOT_VIEW_LABEL = "近14天没有";
|
|
53
|
+
|
|
54
|
+
export const RECOMMEND_CARD_SELECTOR = [
|
|
55
|
+
".candidate-card-wrap .card-inner[data-geek]",
|
|
56
|
+
".candidate-card-wrap [data-geek]",
|
|
57
|
+
"li.geek-info-card a[data-geekid]",
|
|
58
|
+
"a[data-geekid]"
|
|
59
|
+
].join(", ");
|
|
60
|
+
|
|
61
|
+
export const RECOMMEND_LIST_CONTAINER_SELECTORS = Object.freeze([
|
|
62
|
+
".recommend-list",
|
|
63
|
+
".recommend-list-wrap",
|
|
64
|
+
".candidate-list",
|
|
65
|
+
".candidate-card-list",
|
|
66
|
+
".candidate-card-wrap-list",
|
|
67
|
+
".geek-list",
|
|
68
|
+
".geek-list-wrap",
|
|
69
|
+
".card-list",
|
|
70
|
+
".list-wrap",
|
|
71
|
+
".content-list"
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
export const RECOMMEND_END_REFRESH_SELECTOR = [
|
|
75
|
+
".btn",
|
|
76
|
+
"button",
|
|
77
|
+
'[role="button"]',
|
|
78
|
+
'[class*="refresh"]',
|
|
79
|
+
'[ka*="refresh"]',
|
|
80
|
+
"a"
|
|
81
|
+
].join(", ");
|
|
82
|
+
|
|
83
|
+
export const RECOMMEND_BOTTOM_MARKER_SELECTORS = Object.freeze([
|
|
84
|
+
".finished-wrap",
|
|
85
|
+
".no-data-refresh",
|
|
86
|
+
".load-tips",
|
|
87
|
+
".empty-tip",
|
|
88
|
+
".empty-text",
|
|
89
|
+
".no-data",
|
|
90
|
+
"[class*=\"finished\"]",
|
|
91
|
+
"[class*=\"load-tips\"]"
|
|
92
|
+
]);
|
|
93
|
+
|
|
94
|
+
export const DETAIL_POPUP_SELECTORS = Object.freeze([
|
|
95
|
+
".dialog-wrap.active",
|
|
96
|
+
".boss-popup__wrapper",
|
|
97
|
+
".boss-popup_wrapper",
|
|
98
|
+
".boss-dialog_wrapper",
|
|
99
|
+
".boss-dialog",
|
|
100
|
+
".resume-item-detail",
|
|
101
|
+
".geek-detail-modal",
|
|
102
|
+
'[class*="popup"][class*="wrapper"]',
|
|
103
|
+
'[class*="dialog"][class*="wrapper"]'
|
|
104
|
+
]);
|
|
105
|
+
|
|
106
|
+
export const DETAIL_RESUME_IFRAME_SELECTORS = Object.freeze([
|
|
107
|
+
'iframe[src*="/web/frame/c-resume/"]',
|
|
108
|
+
'iframe[name*="resume"]'
|
|
109
|
+
]);
|
|
110
|
+
|
|
111
|
+
export const DETAIL_CLOSE_SELECTORS = Object.freeze([
|
|
112
|
+
".boss-popup__close",
|
|
113
|
+
".popup-close",
|
|
114
|
+
".modal-close",
|
|
115
|
+
".dialog-close",
|
|
116
|
+
".close-btn",
|
|
117
|
+
'button[aria-label*="关闭"]',
|
|
118
|
+
'button[title*="关闭"]',
|
|
119
|
+
".icon-close",
|
|
120
|
+
'[aria-label*="关闭"]',
|
|
121
|
+
'[title*="关闭"]',
|
|
122
|
+
'[class*="close"]'
|
|
123
|
+
]);
|
|
124
|
+
|
|
125
|
+
export const DETAIL_NETWORK_PATTERNS = Object.freeze([
|
|
126
|
+
/\/wapi\/zpjob\/view\/geek\/info\b/i,
|
|
127
|
+
/\/wapi\/zpitem\/web\/boss\/[^?#]*\/geek\/info\b/i,
|
|
128
|
+
/\/boss\/[^?#]*\/geek\/info\b/i,
|
|
129
|
+
/\/geek\/info\b/i,
|
|
130
|
+
/\/web\/frame\/c-resume\//i,
|
|
131
|
+
/resume/i
|
|
132
|
+
]);
|
|
133
|
+
|
|
134
|
+
export const FAVORITE_BUTTON_SELECTORS = Object.freeze([
|
|
135
|
+
".like-icon-and-text",
|
|
136
|
+
".resume-footer.item-operate [class*=\"collect\"]",
|
|
137
|
+
".resume-footer.item-operate [class*=\"favorite\"]",
|
|
138
|
+
".resume-footer.item-operate [class*=\"like\"]",
|
|
139
|
+
".resume-footer-wrap [class*=\"collect\"]",
|
|
140
|
+
".resume-footer-wrap [class*=\"favorite\"]",
|
|
141
|
+
".resume-footer-wrap [class*=\"like\"]",
|
|
142
|
+
".resume-footer [class*=\"collect\"]",
|
|
143
|
+
".resume-footer [class*=\"favorite\"]",
|
|
144
|
+
".resume-footer [class*=\"like\"]",
|
|
145
|
+
".resume-footer.item-operate button",
|
|
146
|
+
".resume-footer.item-operate .btn",
|
|
147
|
+
".resume-footer.item-operate span",
|
|
148
|
+
".resume-footer-wrap button",
|
|
149
|
+
".resume-footer-wrap .btn",
|
|
150
|
+
".resume-footer-wrap span",
|
|
151
|
+
".resume-footer button",
|
|
152
|
+
".resume-footer .btn",
|
|
153
|
+
".resume-footer span"
|
|
154
|
+
]);
|
|
155
|
+
|
|
156
|
+
export const GREET_BUTTON_RECOMMEND_SELECTORS = Object.freeze([
|
|
157
|
+
"button.btn-v2.btn-sure-v2.btn-greet",
|
|
158
|
+
".resume-footer.item-operate button.btn-v2",
|
|
159
|
+
".resume-footer-wrap button.btn-v2",
|
|
160
|
+
".resume-footer.item-operate button",
|
|
161
|
+
".resume-footer-wrap button",
|
|
162
|
+
".resume-footer button",
|
|
163
|
+
"button[class*=\"greet\"]",
|
|
164
|
+
"button[class*=\"sure\"]"
|
|
165
|
+
]);
|
|
@@ -310,12 +310,17 @@ export async function readRecommendDetailHtml(client, detailState) {
|
|
|
310
310
|
};
|
|
311
311
|
}
|
|
312
312
|
|
|
313
|
-
export function isStaleRecommendNodeError(error) {
|
|
314
|
-
const message = String(error?.message || error || "");
|
|
315
|
-
return /Could not find node with given id|No node with given id|Node is detached|Cannot find node/i.test(message);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
export
|
|
313
|
+
export function isStaleRecommendNodeError(error) {
|
|
314
|
+
const message = String(error?.message || error || "");
|
|
315
|
+
return /Could not find node with given id|No node with given id|Node is detached|Cannot find node/i.test(message);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export function isRecommendDetailOpenMissError(error) {
|
|
319
|
+
const message = String(error?.message || error || "");
|
|
320
|
+
return /Candidate detail did not open|no known detail selectors mounted/i.test(message);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export async function findRecommendCardNodeForCandidateKey(client, {
|
|
319
324
|
candidateKey = "",
|
|
320
325
|
rootState = null,
|
|
321
326
|
targetUrl = "",
|
|
@@ -448,18 +453,20 @@ export async function openRecommendCardDetailWithFreshRetry(client, {
|
|
|
448
453
|
card_candidate: currentCandidate,
|
|
449
454
|
retry_attempts: attempts
|
|
450
455
|
};
|
|
451
|
-
} catch (error) {
|
|
452
|
-
const stale = isStaleRecommendNodeError(error);
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
456
|
+
} catch (error) {
|
|
457
|
+
const stale = isStaleRecommendNodeError(error);
|
|
458
|
+
const detailOpenMiss = isRecommendDetailOpenMissError(error);
|
|
459
|
+
attempts.push({
|
|
460
|
+
attempt: attemptIndex + 1,
|
|
461
|
+
node_id: currentNodeId,
|
|
462
|
+
stale_node: stale,
|
|
463
|
+
detail_open_miss: detailOpenMiss,
|
|
464
|
+
error: error?.message || String(error)
|
|
465
|
+
});
|
|
466
|
+
if ((!stale && !detailOpenMiss) || attemptIndex >= limit - 1 || !candidateKey) {
|
|
467
|
+
error.recommend_detail_open_attempts = attempts;
|
|
468
|
+
throw error;
|
|
469
|
+
}
|
|
463
470
|
|
|
464
471
|
const resolved = await findRecommendCardNodeForCandidateKey(client, {
|
|
465
472
|
candidateKey,
|