59 lines
2.1 KiB
TypeScript
59 lines
2.1 KiB
TypeScript
/**
|
|
* Auto-apply worker (Playwright).
|
|
*
|
|
* Usage:
|
|
* npm i -D playwright && npx playwright install chromium # one-time
|
|
* npx tsx worker/apply.ts <jobId> [--submit]
|
|
*
|
|
* Safety model:
|
|
* - WITHOUT --submit it fills the form, screenshots every step, and STOPS
|
|
* before the final submit (dry run). You review screenshots in worker/out/.
|
|
* - WITH --submit it still pauses on CAPTCHAs/Cloudflare (headed mode) and
|
|
* waits for you to solve them; it only clicks submit on adapter-known forms.
|
|
*/
|
|
import { PrismaClient } from "@prisma/client";
|
|
import { adapters } from "./adapters";
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
async function main() {
|
|
const [jobId, ...flags] = process.argv.slice(2);
|
|
const submit = flags.includes("--submit");
|
|
if (!jobId) {
|
|
console.error("usage: npx tsx worker/apply.ts <jobId> [--submit]");
|
|
process.exit(1);
|
|
}
|
|
const job = await prisma.job.findUnique({ where: { id: jobId } });
|
|
if (!job) throw new Error("job not found");
|
|
const profile = await prisma.profile.findUnique({ where: { id: "main" } });
|
|
if (!profile) throw new Error("no profile — fill in /profile first");
|
|
const url = job.applyUrl ?? job.url;
|
|
if (!url) throw new Error("job has no applyUrl/url");
|
|
|
|
const adapter = adapters.find((a) => a.matches(url));
|
|
if (!adapter) {
|
|
console.error(`No adapter matches ${url}.\nKnown adapters: ${adapters.map((a) => a.name).join(", ")}\nUse the in-app Apply Wizard (semi-auto) instead.`);
|
|
process.exit(2);
|
|
}
|
|
|
|
console.log(`Adapter: ${adapter.name} · submit=${submit}`);
|
|
const log = await adapter.run({ job, profile, submit });
|
|
|
|
await prisma.application.create({
|
|
data: {
|
|
jobId,
|
|
method: "auto",
|
|
submittedAt: submit && log.submitted ? new Date() : null,
|
|
log: log.lines.join("\n"),
|
|
},
|
|
});
|
|
if (submit && log.submitted) {
|
|
await prisma.job.update({ where: { id: jobId }, data: { status: "applied" } });
|
|
}
|
|
console.log(log.submitted ? "SUBMITTED ✅" : "DRY RUN complete — review worker/out/ screenshots, re-run with --submit to finish.");
|
|
}
|
|
|
|
main()
|
|
.catch((e) => { console.error(e); process.exit(1); })
|
|
.finally(() => prisma.$disconnect());
|