openings 0.1.44 → 0.1.46
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/.codex-plugin/plugin.json +1 -1
- package/data/companies.json +66 -0
- package/package.json +1 -1
- package/src/crawl-reporting.ts +27 -9
- package/src/version.ts +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openings",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.46",
|
|
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/data/companies.json
CHANGED
|
@@ -108414,5 +108414,71 @@
|
|
|
108414
108414
|
"checkedAt": "2026-09-17T10:47:14.367307Z",
|
|
108415
108415
|
"canonicalSourceUrl": "https://eofh.fa.em2.oraclecloud.com/hcmUI/CandidateExperience/en/sites/CX/requisitions"
|
|
108416
108416
|
}
|
|
108417
|
+
},
|
|
108418
|
+
"youtrip": {
|
|
108419
|
+
"name": "YouTrip",
|
|
108420
|
+
"ats": "workable",
|
|
108421
|
+
"token": "youtrip",
|
|
108422
|
+
"cohorts": [
|
|
108423
|
+
"IN"
|
|
108424
|
+
],
|
|
108425
|
+
"sourceUrl": "https://apply.workable.com/youtrip/",
|
|
108426
|
+
"discoveredFrom": {
|
|
108427
|
+
"channel": "market_signal",
|
|
108428
|
+
"reference": "adzuna india mobile-role sample, 2026-09-17"
|
|
108429
|
+
},
|
|
108430
|
+
"verification": {
|
|
108431
|
+
"observedCompanyName": "YouTrip",
|
|
108432
|
+
"identityEvidence": "provider_board",
|
|
108433
|
+
"contentType": "application/json",
|
|
108434
|
+
"payloadVersion": "workable-jobs:v1",
|
|
108435
|
+
"jobCount": 49,
|
|
108436
|
+
"checkedAt": "2026-09-17T17:02:41.814291Z",
|
|
108437
|
+
"canonicalSourceUrl": "https://apply.workable.com/youtrip/"
|
|
108438
|
+
}
|
|
108439
|
+
},
|
|
108440
|
+
"quince": {
|
|
108441
|
+
"name": "Quince",
|
|
108442
|
+
"ats": "greenhouse",
|
|
108443
|
+
"token": "quince",
|
|
108444
|
+
"cohorts": [
|
|
108445
|
+
"IN"
|
|
108446
|
+
],
|
|
108447
|
+
"sourceUrl": "https://job-boards.greenhouse.io/quince",
|
|
108448
|
+
"discoveredFrom": {
|
|
108449
|
+
"channel": "market_signal",
|
|
108450
|
+
"reference": "adzuna india mobile-role sample, 2026-09-17"
|
|
108451
|
+
},
|
|
108452
|
+
"verification": {
|
|
108453
|
+
"observedCompanyName": "Quince",
|
|
108454
|
+
"identityEvidence": "provider_board",
|
|
108455
|
+
"contentType": "application/json",
|
|
108456
|
+
"payloadVersion": "greenhouse-boards:v1",
|
|
108457
|
+
"jobCount": 133,
|
|
108458
|
+
"checkedAt": "2026-09-17T17:02:41.814291Z",
|
|
108459
|
+
"canonicalSourceUrl": "https://job-boards.greenhouse.io/quince"
|
|
108460
|
+
}
|
|
108461
|
+
},
|
|
108462
|
+
"opentable": {
|
|
108463
|
+
"name": "OpenTable",
|
|
108464
|
+
"ats": "greenhouse",
|
|
108465
|
+
"token": "opentable",
|
|
108466
|
+
"cohorts": [
|
|
108467
|
+
"IN"
|
|
108468
|
+
],
|
|
108469
|
+
"sourceUrl": "https://job-boards.greenhouse.io/opentable",
|
|
108470
|
+
"discoveredFrom": {
|
|
108471
|
+
"channel": "market_signal",
|
|
108472
|
+
"reference": "adzuna india mobile-role sample, 2026-09-17"
|
|
108473
|
+
},
|
|
108474
|
+
"verification": {
|
|
108475
|
+
"observedCompanyName": "OpenTable",
|
|
108476
|
+
"identityEvidence": "provider_board",
|
|
108477
|
+
"contentType": "application/json",
|
|
108478
|
+
"payloadVersion": "greenhouse-boards:v1",
|
|
108479
|
+
"jobCount": 107,
|
|
108480
|
+
"checkedAt": "2026-09-17T17:02:41.814291Z",
|
|
108481
|
+
"canonicalSourceUrl": "https://job-boards.greenhouse.io/opentable"
|
|
108482
|
+
}
|
|
108417
108483
|
}
|
|
108418
108484
|
}
|
package/package.json
CHANGED
package/src/crawl-reporting.ts
CHANGED
|
@@ -27,19 +27,37 @@ export function resolveAggregatorUrl(value: string | undefined): string | undefi
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/** Posts each successfully crawled partition to the aggregator. Only job data is sent, never resume content. */
|
|
30
|
-
export function createCrawlReporter(options: { url: string; fetcher?: Fetch; timeoutMs?: number }) {
|
|
30
|
+
export function createCrawlReporter(options: { url: string; fetcher?: Fetch; timeoutMs?: number; attempts?: number; sleep?: (ms: number) => Promise<void> }) {
|
|
31
31
|
const fetcher = options.fetcher ?? globalThis.fetch;
|
|
32
32
|
const target = endpoint(options.url, "v1/crawls");
|
|
33
|
+
const attempts = Math.max(1, options.attempts ?? 3);
|
|
34
|
+
const sleep = options.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));
|
|
33
35
|
return async (source: Company, partition: JobPartition): Promise<void> => {
|
|
34
36
|
const payload: CrawlReportPayload = { version: 1, source: { slug: source.slug, ats: source.ats, token: source.token }, fetchedAt: partition.fetchedAt, jobs: partition.jobs };
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
const body = Bun.gzipSync(JSON.stringify(payload));
|
|
38
|
+
let last: Error | undefined;
|
|
39
|
+
// A crawl that ends while the aggregator is restarting used to lose its whole report in silence.
|
|
40
|
+
// Retry the failures worth retrying: a refused connection, a timeout, or the server being briefly unwell.
|
|
41
|
+
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
|
42
|
+
try {
|
|
43
|
+
const response = await fetcher(target, {
|
|
44
|
+
method: "POST",
|
|
45
|
+
headers: { "content-type": "application/json", "content-encoding": "gzip" },
|
|
46
|
+
body,
|
|
47
|
+
// Big employers send tens of megabytes and the aggregator ingests one report at a time; give them room.
|
|
48
|
+
signal: AbortSignal.timeout(options.timeoutMs ?? 120_000),
|
|
49
|
+
});
|
|
50
|
+
if (response.ok) return;
|
|
51
|
+
// A rejected report will be rejected again: the catalog disagrees, or the payload is too large.
|
|
52
|
+
if (response.status < 500) throw new Error(`Aggregator rejected crawl report: HTTP ${response.status}`);
|
|
53
|
+
last = new Error(`Aggregator returned HTTP ${response.status}`);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (error instanceof Error && error.message.startsWith("Aggregator rejected")) throw error;
|
|
56
|
+
last = error instanceof Error ? error : new Error(String(error));
|
|
57
|
+
}
|
|
58
|
+
if (attempt < attempts) await sleep(attempt * 5_000);
|
|
59
|
+
}
|
|
60
|
+
throw last ?? new Error("Crawl report failed");
|
|
43
61
|
};
|
|
44
62
|
}
|
|
45
63
|
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = "0.1.
|
|
1
|
+
export const VERSION = "0.1.46";
|