openings 0.1.8 → 0.1.9

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openings",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Find evidence-grounded jobs, including relevant roles you may not have searched for, without accounts or API keys.",
5
5
  "author": { "name": "Openings contributors" },
6
6
  "license": "MIT",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openings",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "A free, candidate-safe job-search substrate for AI agents",
5
5
  "license": "MIT",
6
6
  "repository": { "type": "git", "url": "git+https://github.com/abhay-avagama/hiring-agent.git" },
package/src/locations.ts CHANGED
@@ -101,12 +101,26 @@ function detectRegions(location: string, description: string): string[] {
101
101
  return [...new Set([...fromLocation, ...fromDescription])];
102
102
  }
103
103
 
104
+ /** US state and district postal codes. Many collide with ISO country codes (IN, CA, DE, CO, GA, ID, IL, LA, MA, MD, MO, MT, NE, PA, SC, SD, TN, VA). */
105
+ const US_STATE_CODES = new Set(["AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY", "DC"]);
106
+ const US_CITY_STATE = /,\s*([A-Z]{2})(?=\s*(?:$|,|\d{5}|\(|\/|-))/g;
107
+
104
108
  function detectCountries(location: string): string[] {
105
- const matches: string[] = [];
109
+ const byName: string[] = [];
110
+ const byCode: string[] = [];
106
111
  for (const rule of countryRules()) {
107
- if (rule.location.test(location) || rule.codeLocation.test(location)) matches.push(rule.code);
112
+ if (rule.location.test(location)) byName.push(rule.code);
113
+ else if (rule.codeLocation.test(location)) byCode.push(rule.code);
108
114
  }
109
- return matches;
115
+ // "Indianapolis, IN" is Indiana, not India: a bare code in the US "City, ST" position is a state unless a country name
116
+ // or a known Indian place says otherwise.
117
+ // Case matters: "Berlin, de" is a lowercase country code, "Gary, IN" is a state.
118
+ const stateCodes = [...location.matchAll(US_CITY_STATE)].map((match) => match[1]!).filter((code) => US_STATE_CODES.has(code));
119
+ if (stateCodes.length && byName.length === 0 && !INDIA_PATTERN.test(location)) {
120
+ return [...new Set(["US", ...byCode.filter((code) => !US_STATE_CODES.has(code))])];
121
+ }
122
+ if (byName.includes("US")) return [...new Set([...byName, ...byCode.filter((code) => !US_STATE_CODES.has(code))])];
123
+ return [...new Set([...byName, ...byCode])];
110
124
  }
111
125
 
112
126
  function detectEligibleCountries(description: string): string[] {
package/src/providers.ts CHANGED
@@ -65,7 +65,7 @@ const smartrecruiters: ProviderSpec = {
65
65
  normalize(company, job) {
66
66
  const loc = isRecord(job.location) ? job.location : {};
67
67
  const country = str(loc.country);
68
- const location = str(loc.fullLocation) || [str(loc.city), str(loc.region), country.length === 2 ? country.toUpperCase() : country].filter(Boolean).join(", ") || "Unspecified";
68
+ const location = str(loc.fullLocation) || [str(loc.city), str(loc.region), countryLabel(country)].filter(Boolean).join(", ") || "Unspecified";
69
69
  const remote = loc.remote === true;
70
70
  return classifyJob({
71
71
  id: `smartrecruiters:${company.slug}:${str(job.id)}`, company: company.name, title: str(job.name), location,
@@ -168,7 +168,7 @@ const freshteam: ProviderSpec = {
168
168
  payloadVersion: () => "freshteam-widget:v1",
169
169
  normalize(company, job) {
170
170
  const branch = isRecord(job.branch) ? job.branch : {};
171
- const location = [str(branch.city), str(branch.state), str(branch.country_code).toUpperCase()].filter(Boolean).join(", ") || (job.remote === true ? "Remote" : "Unspecified");
171
+ const location = [str(branch.city), str(branch.state), countryLabel(str(branch.country_code))].filter(Boolean).join(", ") || (job.remote === true ? "Remote" : "Unspecified");
172
172
  const remote = job.remote === true;
173
173
  return classifyJob({
174
174
  id: `freshteam:${company.slug}:${str(job.unique_id) || str(job.id)}`, company: company.name, title: str(job.title), location,
@@ -196,6 +196,14 @@ export function resolveProviderSource(value: string): { ats: Ats; token: string;
196
196
  return null;
197
197
  }
198
198
 
199
+ const regionNames = new Intl.DisplayNames(["en"], { type: "region" });
200
+ /** ISO code to English name (US -> United States); anything that is not a two-letter code passes through. */
201
+ export function countryLabel(value: string): string {
202
+ const code = value.trim().toUpperCase();
203
+ if (!/^[A-Z]{2}$/.test(code)) return value.trim();
204
+ try { const name = regionNames.of(code); return name && name !== code ? name : value.trim(); } catch { return value.trim(); }
205
+ }
206
+
199
207
  function validToken(value: string | undefined): string | null {
200
208
  return value && /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(value) ? value : null;
201
209
  }
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const VERSION = "0.1.8";
1
+ export const VERSION = "0.1.9";