seahaven-site/_data/jobs.js
Adam Moussa ff66171782
Some checks are pending
Deploy / deploy (push) Waiting to run
feat(careers): render openings from the Paychex job feed (#67)
Load listings at build time so Learn more goes to each Paychex posting, and rebuild on weekday mornings so new roles appear without a code change.
2026-09-24 21:17:17 +00:00

80 lines
2.4 KiB
JavaScript

const FEED_URL = "https://jobs.appone.com/api/portal/v1/companyjobposts/seahaven";
const PORTAL_URL = "https://jobs.appone.com/seahaven";
const ALLOWED_HOSTS = new Set(["apply.appone.com", "jobs.appone.com"]);
function isAllowedJobUrl(value) {
if (typeof value !== "string") return false;
try {
const url = new URL(value);
return url.protocol === "https:" && ALLOWED_HOSTS.has(url.hostname);
} catch {
return false;
}
}
function titleCase(value) {
return value
.replace(/[_-]+/g, " ")
.toLowerCase()
.replace(/\b\w/g, (char) => char.toUpperCase());
}
function formatSalary(salary) {
if (!salary || salary.salaryOption !== "RANGE" || salary.periodType !== "YEAR") {
return null;
}
const { minimum, maximum } = salary;
if (!Number.isFinite(minimum) || !Number.isFinite(maximum)) return null;
const money = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
maximumFractionDigits: 0,
});
return `${money.format(minimum)}\u2013${money.format(maximum)} per year`;
}
function normalizePost(post) {
if (!post || typeof post !== "object") {
throw new Error("Paychex job feed returned a posting that is not an object");
}
const title = typeof post.jobTitle === "string" ? post.jobTitle.trim() : "";
if (!title) {
throw new Error("Paychex job feed returned a posting without a title");
}
if (!isAllowedJobUrl(post.jobPostUrl)) {
throw new Error(`Paychex job feed returned an unexpected apply URL for "${title}"`);
}
return {
title,
url: post.jobPostUrl,
location: typeof post.location === "string" ? post.location.trim() : "",
jobType: typeof post.jobType === "string" ? post.jobType.trim() : "",
workplaceType: typeof post.workplaceType === "string" && post.workplaceType.trim()
? titleCase(post.workplaceType.trim())
: "",
salary: formatSalary(post.salary),
};
}
module.exports = async function () {
const response = await fetch(FEED_URL, {
headers: {
Accept: "application/json",
"x-payx-bizpn": "Load Company Job Portal",
},
signal: AbortSignal.timeout(15000),
});
if (!response.ok) {
throw new Error(`Paychex job feed request failed (${response.status})`);
}
const data = await response.json();
if (!data || !Array.isArray(data.jobPosts)) {
throw new Error("Paychex job feed is missing jobPosts");
}
return {
portalUrl: PORTAL_URL,
posts: data.jobPosts.map(normalizePost),
};
};