job-pro 1.0.4 → 1.0.6
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/dist/apply.js +181 -173
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/apply.js
CHANGED
|
@@ -437,21 +437,16 @@ export async function submitApplication(staged, target, options = {}) {
|
|
|
437
437
|
if (options.extraHeaders) {
|
|
438
438
|
Object.assign(headers, options.extraHeaders);
|
|
439
439
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
response = await fetch(url, {
|
|
443
|
-
method: staged.submit_method ?? "POST",
|
|
444
|
-
headers,
|
|
445
|
-
body: fd,
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
catch (err) {
|
|
440
|
+
const r = await fetchWithRetry(url, { method: staged.submit_method ?? "POST", headers, body: fd }, "submit");
|
|
441
|
+
if (!r.ok) {
|
|
449
442
|
return {
|
|
450
443
|
ok: false,
|
|
451
444
|
posted_to: url,
|
|
452
|
-
|
|
445
|
+
status: r.status,
|
|
446
|
+
message: r.message,
|
|
453
447
|
};
|
|
454
448
|
}
|
|
449
|
+
const response = r.response;
|
|
455
450
|
let preview = "";
|
|
456
451
|
try {
|
|
457
452
|
preview = (await response.text()).slice(0, 4000);
|
|
@@ -581,33 +576,20 @@ export async function executeFeishu3Step(staged, session, target) {
|
|
|
581
576
|
const sessionHeaders = sessionHeaderBag(session, host);
|
|
582
577
|
// STEP 1 — upload tokens
|
|
583
578
|
const step1Url = debug ? target.url : `${apiRoot}/attachment/upload/tokens`;
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
catch (err) {
|
|
597
|
-
steps.push({ step: "upload-tokens", url: step1Url, status: 0, ok: false, message: String(err) });
|
|
598
|
-
return { ok: false, posted_to: step1Url, message: "step 1 network error", steps };
|
|
599
|
-
}
|
|
600
|
-
const step1Body = await step1Resp.text();
|
|
601
|
-
steps.push({
|
|
602
|
-
step: "upload-tokens",
|
|
603
|
-
url: step1Url,
|
|
604
|
-
status: step1Resp.status,
|
|
605
|
-
ok: step1Resp.ok,
|
|
606
|
-
message: step1Body.slice(0, 200),
|
|
607
|
-
});
|
|
608
|
-
if (!step1Resp.ok) {
|
|
609
|
-
return { ok: false, posted_to: step1Url, status: step1Resp.status, message: "step 1 failed (upload tokens)", steps, response_preview: step1Body.slice(0, 4000) };
|
|
579
|
+
const s1 = await doStep("upload-tokens", step1Url, {
|
|
580
|
+
method: "POST",
|
|
581
|
+
headers: {
|
|
582
|
+
...sessionHeaders,
|
|
583
|
+
"Content-Type": "application/json",
|
|
584
|
+
Accept: "application/json, text/plain, */*",
|
|
585
|
+
},
|
|
586
|
+
body: JSON.stringify({ filename, file_size: fileSize }),
|
|
587
|
+
}, steps);
|
|
588
|
+
if (!s1.ok) {
|
|
589
|
+
return { ok: false, posted_to: step1Url, status: s1.status, message: `step 1 failed: ${s1.message}`, steps };
|
|
610
590
|
}
|
|
591
|
+
const step1Resp = s1.response;
|
|
592
|
+
const step1Body = s1.text;
|
|
611
593
|
// In debug mode, we don't actually have a presigned URL — short-circuit.
|
|
612
594
|
if (debug) {
|
|
613
595
|
return {
|
|
@@ -645,23 +627,14 @@ export async function executeFeishu3Step(staged, session, target) {
|
|
|
645
627
|
? new FileCtor([new Uint8Array(resumeBytes)], filename, { type: "application/pdf" })
|
|
646
628
|
: new Blob([new Uint8Array(resumeBytes)], { type: "application/pdf" });
|
|
647
629
|
uploadFd.append("file", filePart, filename);
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
630
|
+
const s2 = await doStep("upload-file", upload_url, { method: "POST", body: uploadFd }, steps);
|
|
631
|
+
if (!s2.ok) {
|
|
632
|
+
return { ok: false, posted_to: upload_url, status: s2.status, message: `step 2 failed: ${s2.message}`, steps };
|
|
651
633
|
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
steps.push({
|
|
657
|
-
step: "upload-file",
|
|
658
|
-
url: upload_url,
|
|
659
|
-
status: step2Resp.status,
|
|
660
|
-
ok: step2Resp.ok,
|
|
661
|
-
message: `HTTP ${step2Resp.status}`,
|
|
662
|
-
});
|
|
663
|
-
if (!step2Resp.ok) {
|
|
664
|
-
return { ok: false, posted_to: upload_url, status: step2Resp.status, message: "step 2 failed (upload to CDN)", steps };
|
|
634
|
+
// s2 already pushed to steps via doStep; if upstream returned non-2xx
|
|
635
|
+
// (after retries on 5xx), surface that.
|
|
636
|
+
if (!s2.response.ok) {
|
|
637
|
+
return { ok: false, posted_to: upload_url, status: s2.response.status, message: "step 2 failed (upload to CDN)", steps };
|
|
665
638
|
}
|
|
666
639
|
// STEP 3 — resume/apply
|
|
667
640
|
const applicantInfo = {};
|
|
@@ -676,39 +649,107 @@ export async function executeFeishu3Step(staged, session, target) {
|
|
|
676
649
|
applicant_info: applicantInfo,
|
|
677
650
|
};
|
|
678
651
|
const step3Url = `${apiRoot}/resume/apply`;
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
catch (err) {
|
|
692
|
-
steps.push({ step: "resume-apply", url: step3Url, status: 0, ok: false, message: String(err) });
|
|
693
|
-
return { ok: false, posted_to: step3Url, message: "step 3 network error", steps };
|
|
652
|
+
const s3 = await doStep("resume-apply", step3Url, {
|
|
653
|
+
method: "POST",
|
|
654
|
+
headers: {
|
|
655
|
+
...sessionHeaders,
|
|
656
|
+
"Content-Type": "application/json",
|
|
657
|
+
Accept: "application/json, text/plain, */*",
|
|
658
|
+
},
|
|
659
|
+
body: JSON.stringify(step3Body),
|
|
660
|
+
}, steps);
|
|
661
|
+
if (!s3.ok) {
|
|
662
|
+
return { ok: false, posted_to: step3Url, status: s3.status, message: `step 3 failed: ${s3.message}`, steps };
|
|
694
663
|
}
|
|
695
|
-
const step3Text = await step3Resp.text();
|
|
696
|
-
steps.push({
|
|
697
|
-
step: "resume-apply",
|
|
698
|
-
url: step3Url,
|
|
699
|
-
status: step3Resp.status,
|
|
700
|
-
ok: step3Resp.ok,
|
|
701
|
-
message: step3Text.slice(0, 200),
|
|
702
|
-
});
|
|
703
664
|
return {
|
|
704
|
-
ok:
|
|
705
|
-
status:
|
|
665
|
+
ok: s3.response.ok,
|
|
666
|
+
status: s3.response.status,
|
|
706
667
|
posted_to: step3Url,
|
|
707
|
-
response_preview:
|
|
708
|
-
message:
|
|
668
|
+
response_preview: s3.text,
|
|
669
|
+
message: s3.response.ok ? "Feishu 3-step submission accepted" : `step 3 rejected: HTTP ${s3.response.status}`,
|
|
709
670
|
steps,
|
|
710
671
|
};
|
|
711
672
|
}
|
|
673
|
+
async function fetchWithRetry(url, init, label, log) {
|
|
674
|
+
const maxRetries = Math.max(0, Math.min(5, Number.parseInt(process.env.JOB_PRO_RETRY ?? "2", 10) || 2));
|
|
675
|
+
let lastErr = "";
|
|
676
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
677
|
+
let response = null;
|
|
678
|
+
try {
|
|
679
|
+
response = await fetch(url, init);
|
|
680
|
+
}
|
|
681
|
+
catch (err) {
|
|
682
|
+
lastErr = `network error: ${err instanceof Error ? err.message : String(err)}`;
|
|
683
|
+
log?.push({ attempt: attempt + 1, ok: false, message: `${label}: ${lastErr}` });
|
|
684
|
+
// Network errors are retryable. Back off and try again.
|
|
685
|
+
if (attempt < maxRetries) {
|
|
686
|
+
await sleep(retryDelayMs(attempt));
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
return { ok: false, message: lastErr };
|
|
690
|
+
}
|
|
691
|
+
// 4xx → user error, don't retry.
|
|
692
|
+
if (response.status >= 400 && response.status < 500) {
|
|
693
|
+
log?.push({ attempt: attempt + 1, ok: false, status: response.status, message: `${label}: HTTP ${response.status} (no retry — 4xx)` });
|
|
694
|
+
return { ok: false, status: response.status, message: `HTTP ${response.status}: ${response.statusText}` };
|
|
695
|
+
}
|
|
696
|
+
// 5xx → server error, retry.
|
|
697
|
+
if (response.status >= 500 && attempt < maxRetries) {
|
|
698
|
+
lastErr = `HTTP ${response.status}: ${response.statusText}`;
|
|
699
|
+
log?.push({ attempt: attempt + 1, ok: false, status: response.status, message: `${label}: ${lastErr} (will retry)` });
|
|
700
|
+
await sleep(retryDelayMs(attempt));
|
|
701
|
+
continue;
|
|
702
|
+
}
|
|
703
|
+
log?.push({ attempt: attempt + 1, ok: response.ok, status: response.status, message: `${label}: HTTP ${response.status}` });
|
|
704
|
+
return { ok: true, response };
|
|
705
|
+
}
|
|
706
|
+
return { ok: false, message: lastErr || "exhausted retries" };
|
|
707
|
+
}
|
|
708
|
+
function retryDelayMs(attempt) {
|
|
709
|
+
// Exponential backoff with jitter: 250ms / 500ms / 1s / 2s / 4s, ±25%.
|
|
710
|
+
const base = 250 * Math.pow(2, attempt);
|
|
711
|
+
const jitter = base * (Math.random() * 0.5 - 0.25);
|
|
712
|
+
return Math.round(base + jitter);
|
|
713
|
+
}
|
|
714
|
+
function sleep(ms) {
|
|
715
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Family-executor convenience wrapper. Combines fetchWithRetry's
|
|
719
|
+
* transient-failure handling with the FeishuStepLog bookkeeping that
|
|
720
|
+
* each executor needs to push into result.steps. Returns the response
|
|
721
|
+
* + decoded text, or the error message; either way appends one entry
|
|
722
|
+
* to `steps[]`.
|
|
723
|
+
*/
|
|
724
|
+
async function doStep(step, url, init, steps) {
|
|
725
|
+
const r = await fetchWithRetry(url, init, step);
|
|
726
|
+
if (!r.ok) {
|
|
727
|
+
steps.push({
|
|
728
|
+
step,
|
|
729
|
+
url,
|
|
730
|
+
status: r.status ?? 0,
|
|
731
|
+
ok: false,
|
|
732
|
+
message: r.message.slice(0, 200),
|
|
733
|
+
});
|
|
734
|
+
return { ok: false, status: r.status, message: r.message };
|
|
735
|
+
}
|
|
736
|
+
const response = r.response;
|
|
737
|
+
let text = "";
|
|
738
|
+
try {
|
|
739
|
+
text = (await response.text()).slice(0, 4000);
|
|
740
|
+
}
|
|
741
|
+
catch {
|
|
742
|
+
/* binary or stream */
|
|
743
|
+
}
|
|
744
|
+
steps.push({
|
|
745
|
+
step,
|
|
746
|
+
url,
|
|
747
|
+
status: response.status,
|
|
748
|
+
ok: response.ok,
|
|
749
|
+
message: text.slice(0, 200) || `HTTP ${response.status}`,
|
|
750
|
+
});
|
|
751
|
+
return { ok: true, response, text };
|
|
752
|
+
}
|
|
712
753
|
/** Build the headers bag used by every Feishu/Beisen/Moka step. */
|
|
713
754
|
function sessionHeaderBag(session, targetHost) {
|
|
714
755
|
const out = {
|
|
@@ -799,42 +840,32 @@ export async function executeMokaApply(staged, session, target) {
|
|
|
799
840
|
fd.append("resume", filePart, filename);
|
|
800
841
|
const steps = [];
|
|
801
842
|
const sessionHeaders = sessionHeaderBag(session, host);
|
|
802
|
-
// Pre-flight limit check (optional — skip in debug since we'd redirect)
|
|
843
|
+
// Pre-flight limit check (optional — skip in debug since we'd redirect).
|
|
844
|
+
// Best-effort; we ignore failures here because the upstream submit will
|
|
845
|
+
// surface any blocker more authoritatively.
|
|
803
846
|
if (!debug && session) {
|
|
804
847
|
const lc = `${apiRoot}/api/outer/ats-apply/website/applicant-limit-check`;
|
|
805
|
-
|
|
806
|
-
const resp = await fetch(lc, {
|
|
807
|
-
method: "POST",
|
|
808
|
-
headers: { ...sessionHeaders, "Content-Type": "application/json" },
|
|
809
|
-
body: JSON.stringify({ orgId: slug, jobId: staged.post_id }),
|
|
810
|
-
});
|
|
811
|
-
const txt = (await resp.text()).slice(0, 200);
|
|
812
|
-
steps.push({ step: "limit-check", url: lc, status: resp.status, ok: resp.ok, message: txt });
|
|
813
|
-
}
|
|
814
|
-
catch (err) {
|
|
815
|
-
steps.push({ step: "limit-check", url: lc, status: 0, ok: false, message: String(err) });
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
// Final submit
|
|
819
|
-
let resp;
|
|
820
|
-
try {
|
|
821
|
-
resp = await fetch(targetUrl, {
|
|
848
|
+
await doStep("limit-check", lc, {
|
|
822
849
|
method: "POST",
|
|
823
|
-
headers: sessionHeaders,
|
|
824
|
-
body:
|
|
825
|
-
});
|
|
826
|
-
}
|
|
827
|
-
catch (err) {
|
|
828
|
-
steps.push({ step: "apply", url: targetUrl, status: 0, ok: false, message: String(err) });
|
|
829
|
-
return { ok: false, posted_to: targetUrl, message: "apply step network error", steps };
|
|
850
|
+
headers: { ...sessionHeaders, "Content-Type": "application/json" },
|
|
851
|
+
body: JSON.stringify({ orgId: slug, jobId: staged.post_id }),
|
|
852
|
+
}, steps);
|
|
830
853
|
}
|
|
831
|
-
|
|
832
|
-
|
|
854
|
+
// Final submit
|
|
855
|
+
const sFinal = await doStep("apply", targetUrl, {
|
|
856
|
+
method: "POST",
|
|
857
|
+
headers: sessionHeaders, // Content-Type: multipart/form-data; boundary set by undici
|
|
858
|
+
body: fd,
|
|
859
|
+
}, steps);
|
|
860
|
+
if (!sFinal.ok) {
|
|
861
|
+
return { ok: false, posted_to: targetUrl, status: sFinal.status, message: `apply failed: ${sFinal.message}`, steps };
|
|
862
|
+
}
|
|
863
|
+
const resp = sFinal.response;
|
|
833
864
|
return {
|
|
834
865
|
ok: resp.ok,
|
|
835
866
|
status: resp.status,
|
|
836
867
|
posted_to: targetUrl,
|
|
837
|
-
response_preview: text,
|
|
868
|
+
response_preview: sFinal.text,
|
|
838
869
|
message: resp.ok ? "Moka apply submitted" : `Moka apply rejected: HTTP ${resp.status}`,
|
|
839
870
|
steps,
|
|
840
871
|
};
|
|
@@ -894,16 +925,12 @@ export async function executeBeisenWecruit(staged, session, target) {
|
|
|
894
925
|
? new FileCtor([new Uint8Array(resumeBytes)], filename, { type: "application/pdf" })
|
|
895
926
|
: new Blob([new Uint8Array(resumeBytes)], { type: "application/pdf" });
|
|
896
927
|
uploadFd.append("file", filePart, filename);
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
}
|
|
901
|
-
catch (err) {
|
|
902
|
-
steps.push({ step: "upload-file", url: step1Url, status: 0, ok: false, message: String(err) });
|
|
903
|
-
return { ok: false, posted_to: step1Url, message: "step 1 network error", steps };
|
|
928
|
+
const s1 = await doStep("upload-file", step1Url, { method: "POST", headers: sessionHeaders, body: uploadFd }, steps);
|
|
929
|
+
if (!s1.ok) {
|
|
930
|
+
return { ok: false, posted_to: step1Url, status: s1.status, message: `step 1 failed: ${s1.message}`, steps };
|
|
904
931
|
}
|
|
905
|
-
const
|
|
906
|
-
|
|
932
|
+
const r1 = s1.response;
|
|
933
|
+
const text1 = s1.text;
|
|
907
934
|
if (debug) {
|
|
908
935
|
return { ok: r1.ok, status: r1.status, posted_to: step1Url, message: "debug: step 1 fired, steps 2+3 skipped", steps, response_preview: text1 };
|
|
909
936
|
}
|
|
@@ -918,36 +945,26 @@ export async function executeBeisenWecruit(staged, session, target) {
|
|
|
918
945
|
catch { /* keep empty */ }
|
|
919
946
|
// STEP 2 — profile info
|
|
920
947
|
const step2Url = `${apiBase}/resume/info/add/${encodeURIComponent(su)}`;
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
catch (err) {
|
|
930
|
-
steps.push({ step: "profile-add", url: step2Url, status: 0, ok: false, message: String(err) });
|
|
931
|
-
return { ok: false, posted_to: step2Url, message: "step 2 network error", steps };
|
|
948
|
+
const s2 = await doStep("profile-add", step2Url, {
|
|
949
|
+
method: "POST",
|
|
950
|
+
headers: { ...sessionHeaders, "Content-Type": "application/json" },
|
|
951
|
+
body: JSON.stringify({ name: applicant.name, email: applicant.email, phone: applicant.phone, attachmentId }),
|
|
952
|
+
}, steps);
|
|
953
|
+
if (!s2.ok) {
|
|
954
|
+
return { ok: false, posted_to: step2Url, status: s2.status, message: `step 2 failed: ${s2.message}`, steps };
|
|
932
955
|
}
|
|
933
|
-
const text2 = (await r2.text()).slice(0, 2000);
|
|
934
|
-
steps.push({ step: "profile-add", url: step2Url, status: r2.status, ok: r2.ok, message: text2.slice(0, 200) });
|
|
935
956
|
// STEP 3 — final delivery
|
|
936
957
|
const step3Url = `${apiBase}/delivery/resume/${encodeURIComponent(su)}`;
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
return { ok: false, posted_to: step3Url, message: "step 3 network error", steps };
|
|
948
|
-
}
|
|
949
|
-
const text3 = (await r3.text()).slice(0, 4000);
|
|
950
|
-
steps.push({ step: "deliver", url: step3Url, status: r3.status, ok: r3.ok, message: text3.slice(0, 200) });
|
|
958
|
+
const s3 = await doStep("deliver", step3Url, {
|
|
959
|
+
method: "POST",
|
|
960
|
+
headers: { ...sessionHeaders, "Content-Type": "application/json" },
|
|
961
|
+
body: JSON.stringify({ postId: staged.post_id, attachmentId }),
|
|
962
|
+
}, steps);
|
|
963
|
+
if (!s3.ok) {
|
|
964
|
+
return { ok: false, posted_to: step3Url, status: s3.status, message: `step 3 failed: ${s3.message}`, steps };
|
|
965
|
+
}
|
|
966
|
+
const r3 = s3.response;
|
|
967
|
+
const text3 = s3.text;
|
|
951
968
|
return {
|
|
952
969
|
ok: r3.ok,
|
|
953
970
|
status: r3.status,
|
|
@@ -1011,16 +1028,12 @@ export async function executeBeisenITalent(staged, session, target) {
|
|
|
1011
1028
|
? new FileCtor([new Uint8Array(resumeBytes)], filename, { type: "application/pdf" })
|
|
1012
1029
|
: new Blob([new Uint8Array(resumeBytes)], { type: "application/pdf" });
|
|
1013
1030
|
uploadFd.append("file", filePart, filename);
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
}
|
|
1018
|
-
catch (err) {
|
|
1019
|
-
steps.push({ step: "upload", url: step1Url, status: 0, ok: false, message: String(err) });
|
|
1020
|
-
return { ok: false, posted_to: step1Url, message: "step 1 network error", steps };
|
|
1031
|
+
const s1 = await doStep("upload", step1Url, { method: "POST", headers: sessionHeaders, body: uploadFd }, steps);
|
|
1032
|
+
if (!s1.ok) {
|
|
1033
|
+
return { ok: false, posted_to: step1Url, status: s1.status, message: `step 1 failed: ${s1.message}`, steps };
|
|
1021
1034
|
}
|
|
1022
|
-
const
|
|
1023
|
-
|
|
1035
|
+
const r1 = s1.response;
|
|
1036
|
+
const text1 = s1.text;
|
|
1024
1037
|
if (debug) {
|
|
1025
1038
|
return { ok: r1.ok, status: r1.status, posted_to: step1Url, message: "debug: step 1 fired, step 2 skipped", steps, response_preview: text1 };
|
|
1026
1039
|
}
|
|
@@ -1034,31 +1047,26 @@ export async function executeBeisenITalent(staged, session, target) {
|
|
|
1034
1047
|
catch { /* keep empty */ }
|
|
1035
1048
|
// STEP 2 — submit apply
|
|
1036
1049
|
const step2Url = `${apiRoot}/api/Apply/SubmitResume`;
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
steps.push({ step: "submit", url: step2Url, status: 0, ok: false, message: String(err) });
|
|
1053
|
-
return { ok: false, posted_to: step2Url, message: "step 2 network error", steps };
|
|
1054
|
-
}
|
|
1055
|
-
const text2 = (await r2.text()).slice(0, 4000);
|
|
1056
|
-
steps.push({ step: "submit", url: step2Url, status: r2.status, ok: r2.ok, message: text2.slice(0, 200) });
|
|
1050
|
+
const s2 = await doStep("submit", step2Url, {
|
|
1051
|
+
method: "POST",
|
|
1052
|
+
headers: { ...sessionHeaders, "Content-Type": "application/json" },
|
|
1053
|
+
body: JSON.stringify({
|
|
1054
|
+
JobAdId: staged.post_id,
|
|
1055
|
+
ResumeId: resumeId,
|
|
1056
|
+
Name: applicant.name,
|
|
1057
|
+
Email: applicant.email,
|
|
1058
|
+
Mobile: applicant.phone,
|
|
1059
|
+
}),
|
|
1060
|
+
}, steps);
|
|
1061
|
+
if (!s2.ok) {
|
|
1062
|
+
return { ok: false, posted_to: step2Url, status: s2.status, message: `step 2 failed: ${s2.message}`, steps };
|
|
1063
|
+
}
|
|
1064
|
+
const r2 = s2.response;
|
|
1057
1065
|
return {
|
|
1058
1066
|
ok: r2.ok,
|
|
1059
1067
|
status: r2.status,
|
|
1060
1068
|
posted_to: step2Url,
|
|
1061
|
-
response_preview:
|
|
1069
|
+
response_preview: s2.text,
|
|
1062
1070
|
message: r2.ok ? "Beisen iTalent submission accepted" : `step 2 rejected: HTTP ${r2.status}`,
|
|
1063
1071
|
steps,
|
|
1064
1072
|
};
|
package/dist/index.js
CHANGED
|
@@ -60,7 +60,7 @@ import { createRequire as require_createRequire } from "node:module";
|
|
|
60
60
|
function require_module() {
|
|
61
61
|
return { createRequire: require_createRequire };
|
|
62
62
|
}
|
|
63
|
-
const VERSION = "1.0.
|
|
63
|
+
const VERSION = "1.0.6";
|
|
64
64
|
const COMPANIES = [
|
|
65
65
|
{ key: "tencent", family: "Bespoke", source: "join.qq.com", label: "Tencent / 腾讯" },
|
|
66
66
|
{ key: "bytedance", family: "Bespoke", source: "jobs.bytedance.com", label: "ByteDance / 字节跳动" },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "job-pro",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Query Chinese big-tech campus recruiting from your terminal. 50 companies, all 50 live. 46 via each company's own API; the 4 with no public canonical feed (Hikvision, CICC, Cainiao, WeBank) surfaced via Liepin as a clearly-labeled third-party fallback. No signup, no token, no server.",
|
|
5
5
|
"homepage": "https://job.ha7ch.com",
|
|
6
6
|
"repository": "https://github.com/HA7CH/job-pro",
|