openings 0.1.15 → 0.1.16

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.15",
3
+ "version": "0.1.16",
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.15",
3
+ "version": "0.1.16",
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/crawler.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { FetchJobsObserver } from "./catalog.ts";
2
- import type { Company, CrawlFailure, CrawlReport, CrawlSourceResult, Job, JobPartition, JobSnapshot } from "./types.ts";
2
+ import { partitionFor, type Company, type CrawlFailure, type CrawlReport, type CrawlSourceResult, type Job, type JobPartition, type JobSnapshot } from "./types.ts";
3
3
 
4
4
  export interface SnapshotStore {
5
5
  read(): Promise<JobSnapshot | null>;
@@ -66,9 +66,9 @@ export function createCrawler(options: CrawlerOptions): Crawler {
66
66
  const considered = sources.length;
67
67
  const cutoff = Date.parse(startedAt) - sourceFreshnessMs;
68
68
  const eligibleSources = (sourceFreshnessMs === 0 ? sources : sources.filter((source) => {
69
- const fetchedAt = Date.parse(partitions[source.slug]?.fetchedAt ?? "");
69
+ const fetchedAt = Date.parse(partitionFor(partitions, source.slug)?.fetchedAt ?? "");
70
70
  return !Number.isFinite(fetchedAt) || fetchedAt <= cutoff;
71
- })).sort((left, right) => partitionTime(partitions[left.slug]?.fetchedAt) - partitionTime(partitions[right.slug]?.fetchedAt));
71
+ })).sort((left, right) => partitionTime(partitionFor(partitions, left.slug)?.fetchedAt) - partitionTime(partitionFor(partitions, right.slug)?.fetchedAt));
72
72
  const selectedSources = sourceLimit > 0 ? eligibleSources.slice(0, sourceLimit) : eligibleSources;
73
73
  let pending = selectedSources;
74
74
  let finalFailures: CrawlFailure[] = [];
@@ -1,6 +1,6 @@
1
1
  import { isEligibleForCountry } from "./locations.ts";
2
2
  import type { SnapshotStore } from "./crawler.ts";
3
- import type { Company, JobSnapshot } from "./types.ts";
3
+ import { partitionFor, type Company, type JobSnapshot } from "./types.ts";
4
4
 
5
5
  export interface CountryJobCoverage {
6
6
  country: string;
@@ -28,7 +28,7 @@ export function createJobCoverageReader(options: { sources: Company[]; store: Sn
28
28
  export function projectJobCoverage(sources: Company[], snapshot: JobSnapshot, countries: string[]): JobCoverageSummary {
29
29
  const normalizedCountries = [...new Set(countries.map(normalizeCountry))];
30
30
  const indexedSources = sources.flatMap((source) => {
31
- const partition = snapshot.partitions[source.slug];
31
+ const partition = partitionFor(snapshot.partitions, source.slug);
32
32
  return partition ? [{ source, jobs: partition.jobs }] : [];
33
33
  });
34
34
 
@@ -1,7 +1,7 @@
1
1
  import type { SnapshotStore } from "./crawler.ts";
2
2
  import { projectJobCoverage, type JobCoverageSummary } from "./job-coverage.ts";
3
3
  import type { CrawlScope } from "./local-jobs.ts";
4
- import type { Company, CrawlReport, JobSnapshot } from "./types.ts";
4
+ import { partitionFor, type Company, type CrawlReport, type JobSnapshot } from "./types.ts";
5
5
 
6
6
  export interface PrepareJobSearchResult {
7
7
  status: "ready" | "partial";
@@ -61,7 +61,7 @@ export function createJobSearchPreparer(options: {
61
61
  function pendingSources(sources: Company[], snapshot: Awaited<ReturnType<SnapshotStore["read"]>>, now: Date, freshnessMs: number): Company[] {
62
62
  const cutoff = now.getTime() - freshnessMs;
63
63
  return sources.filter((source) => {
64
- const fetchedAt = Date.parse(snapshot?.partitions[source.slug]?.fetchedAt ?? "");
64
+ const fetchedAt = Date.parse((snapshot && partitionFor(snapshot.partitions, source.slug))?.fetchedAt ?? "");
65
65
  return !Number.isFinite(fetchedAt) || fetchedAt < cutoff;
66
66
  });
67
67
  }
@@ -71,7 +71,7 @@ function sourceState(sources: Company[], snapshot: NonNullable<Awaited<ReturnTyp
71
71
  let missing = 0;
72
72
  let stale = 0;
73
73
  for (const source of sources) {
74
- const partition = snapshot.partitions[source.slug];
74
+ const partition = partitionFor(snapshot.partitions, source.slug);
75
75
  if (!partition) missing += 1;
76
76
  else {
77
77
  const fetchedAt = Date.parse(partition.fetchedAt);
package/src/runtime.ts CHANGED
@@ -47,7 +47,7 @@ export function createRuntime(options: { dataDir?: string; concurrency?: number;
47
47
  workdayCountries,
48
48
  onCrawled,
49
49
  });
50
- const preparation = createJobSearchPreparer({ sources: companies, store, crawl: preparationLocal.crawl, seed: aggregatorUrl ? (countries) => fetchSeedSnapshot(aggregatorUrl, globalThis.fetch, 20_000, countries) : undefined });
50
+ const preparation = createJobSearchPreparer({ sources: companies, store, crawl: preparationLocal.crawl, seed: aggregatorUrl ? (countries) => fetchSeedSnapshot(aggregatorUrl, globalThis.fetch, 60_000, countries) : undefined });
51
51
  const getSelectedJob = createSelectedJobLookup({
52
52
  getSnapshotJob: async (id) => (await local.get(id, { offline: true, staleDays: 14 })).job,
53
53
  getDetailedJob: (id) => liveCatalog.get(id),
package/src/types.ts CHANGED
@@ -88,6 +88,11 @@ export interface Job extends JobSummary {
88
88
  description: string;
89
89
  }
90
90
 
91
+ /** Partition lookup that ignores inherited properties, so a slug such as "constructor" never resolves to Object.prototype. */
92
+ export function partitionFor<T>(partitions: Record<string, T>, slug: string): T | undefined {
93
+ return Object.hasOwn(partitions, slug) ? partitions[slug] : undefined;
94
+ }
95
+
91
96
  export interface SearchQuery {
92
97
  query?: string;
93
98
  location?: string;
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const VERSION = "0.1.15";
1
+ export const VERSION = "0.1.16";