lazy-apply 0.1.3 → 0.1.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/dist/cli.js CHANGED
@@ -6,7 +6,7 @@ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node
6
6
  import { homedir, hostname, platform, tmpdir, userInfo } from "node:os";
7
7
  import { dirname, join } from "node:path";
8
8
  import { createInterface } from "node:readline/promises";
9
- var VERSION = true ? "0.1.3" : "dev";
9
+ var VERSION = true ? "0.1.5" : "dev";
10
10
  var DEFAULT_APP = "https://lazyapply.online";
11
11
  var HOME = join(homedir(), ".lazy-apply");
12
12
  var CONFIG = join(HOME, "config.json");
package/dist/runner.js CHANGED
@@ -419,6 +419,29 @@ function findEmptyRequired() {
419
419
  for (const lab of labels) {
420
420
  const raw = textOf(lab);
421
421
  const ctl = lab.control;
422
+ const opt = ctl;
423
+ if (opt && /radio|checkbox/.test(opt.type || "") && opt.name) {
424
+ if (seen.has(`name:${opt.name}`)) continue;
425
+ seen.add(`name:${opt.name}`);
426
+ const group = Array.from(document.querySelectorAll(`input[name="${CSS.escape(opt.name)}"]`));
427
+ const required2 = group.some((g) => g.required || g.getAttribute("aria-required") === "true");
428
+ if (!required2 || group.some((g) => g.checked)) continue;
429
+ let node = opt.parentElement, question = "";
430
+ while (node && node !== document.body) {
431
+ if (group.every((g) => node.contains(g))) {
432
+ const q = node.querySelector(".application-label, legend, [class*=question-title], [class*=question] > div:first-child, h3, h4");
433
+ question = clean(textOf(q));
434
+ if (question) break;
435
+ }
436
+ node = node.parentElement;
437
+ }
438
+ const label2 = question || clean(raw);
439
+ if (label2 && !seen.has(label2)) {
440
+ seen.add(label2);
441
+ out.push(label2);
442
+ }
443
+ continue;
444
+ }
422
445
  const box = lab.closest("[data-field-entry-id], fieldset, [class*=field-entry], [class*=question], [class*=field], li") || lab.parentElement;
423
446
  if (!box) continue;
424
447
  const required = /\*|✱/.test(raw) || /required/i.test(lab.className) || !!(ctl && (ctl.hasAttribute("required") || ctl.getAttribute("aria-required") === "true")) || !!box.querySelector("[required], [aria-required=true]");
@@ -1105,6 +1128,12 @@ async function submitGeneric(page) {
1105
1128
  if (/captcha|robot|verify you are human/i.test(text) || await page.locator("iframe[src*=hcaptcha], iframe[src*=recaptcha], iframe[src*=turnstile]").count()) throw new Error("A captcha is shown. Solve it in the window, press Submit there, then use Mark as submitted here.");
1106
1129
  throw new Error("No confirmation text after submit");
1107
1130
  }
1131
+ async function dismissCookieBanner(page) {
1132
+ await page.waitForTimeout(800);
1133
+ const button = page.getByRole("button", { name: /^(dismiss|accept( all)?( cookies)?|got it|i agree|agree|ok(ay)?|allow all)$/i }).filter({ visible: true }).first();
1134
+ if (await button.count().catch(() => 0)) await button.click({ timeout: 3e3 }).catch(() => {
1135
+ });
1136
+ }
1108
1137
  async function fill(app) {
1109
1138
  const notes = [];
1110
1139
  await report(app.id, { status: "filling", notes: ["Runner picked up the application"] });
@@ -1112,6 +1141,7 @@ async function fill(app) {
1112
1141
  const page = await b.newPage({ viewport: { width: 1380, height: 940 } });
1113
1142
  try {
1114
1143
  await page.goto(app.job.applyUrl.replace(/#app$/, ""), { waitUntil: "domcontentloaded" });
1144
+ await dismissCookieBanner(page);
1115
1145
  if (app.job.board === "greenhouse") await fillGreenhouse(page, app, notes);
1116
1146
  else await discoverAndFillGeneric(page, app, notes);
1117
1147
  await page.waitForTimeout(800);
@@ -1225,8 +1255,16 @@ async function loop() {
1225
1255
  if (inFlight.has(app.id)) continue;
1226
1256
  inFlight.add(app.id);
1227
1257
  try {
1228
- if (app.status === "approved" && !live.has(app.id)) await fill(app);
1229
- else if (app.status === "submit_requested") {
1258
+ if (app.status === "approved") {
1259
+ const stale = live.get(app.id);
1260
+ if (stale) {
1261
+ await stale.page.close().catch(() => {
1262
+ });
1263
+ live.delete(app.id);
1264
+ log(`refilling ${app.id}: the application changed after it was filled`);
1265
+ }
1266
+ await fill(app);
1267
+ } else if (app.status === "submit_requested") {
1230
1268
  await paceSubmit(app.job.applyUrl);
1231
1269
  await submit(app);
1232
1270
  lastSubmitAt = Date.now();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lazy-apply",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "The Lazy Apply runner: fills your approved job applications in Chrome on your own computer. Run `npx lazy-apply`.",
5
5
  "type": "module",
6
6
  "bin": { "lazy-apply": "dist/cli.js" },