mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-09-17 08:36:25 +00:00
chore(freehire-search): point at freehire.me (domain migrated from freehire.dev) (#229)
freehire moved its primary domain from freehire.dev to freehire.me. Update the freehire-search skill's default API base URL, help text, docs, and examples. Backward-compatible: FREEHIRE_API_URL still overrides the base (self-hosting), and normalizeSlug is host-agnostic so pasted freehire.dev/jobs/<slug> URLs still resolve. The GitHub repo link (github.com/strelov1/freehire) is unchanged. All 27 CLI tests pass; the freehire.me API answers 200 for /jobs/search + /jobs/facets.
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
# freehire-cli
|
||||
|
||||
CLI for searching the [freehire.dev](https://freehire.dev) job aggregator across
|
||||
CLI for searching the [freehire.me](https://freehire.me) job aggregator across
|
||||
**many markets** (tech-focused), via its public JSON API.
|
||||
|
||||
**Data source**: freehire.dev REST API (`/api/v1/jobs/search`, `/api/v1/jobs/facets`, `/api/v1/jobs/{slug}`).
|
||||
**Data source**: freehire.me REST API (`/api/v1/jobs/search`, `/api/v1/jobs/facets`, `/api/v1/jobs/{slug}`).
|
||||
**Authentication**: None required — reads are public (only tracking mutations need a key, and those are out of scope here).
|
||||
**Dependencies**: None (plain `bun` + `fetch`). `bun install` is optional and only pulls dev type defs.
|
||||
|
||||
> **Hosted-service dependency.** This skill talks to freehire.dev, a personal
|
||||
> **Hosted-service dependency.** This skill talks to freehire.me, a personal
|
||||
> project maintained on a **best-effort basis with no formal SLA**. If the API is
|
||||
> unreachable the CLI exits non-zero with a clear error rather than hanging, so an
|
||||
> outage degrades gracefully instead of breaking the caller. Point `FREEHIRE_API_URL`
|
||||
@@ -25,7 +25,7 @@ The CLI runs without any install because it has zero runtime dependencies.
|
||||
|
||||
## Self-hosting / base URL
|
||||
|
||||
The base URL defaults to `https://freehire.dev` and is overridable with an env var:
|
||||
The base URL defaults to `https://freehire.me` and is overridable with an env var:
|
||||
|
||||
```bash
|
||||
FREEHIRE_API_URL=http://localhost:8080 bun run src/cli.ts search -q "go"
|
||||
@@ -83,5 +83,5 @@ See `../SKILL.md` for the full flag reference and the hosted-dependency note.
|
||||
|
||||
Facet values come from freehire's controlled vocabularies. Discover the live
|
||||
values (with counts) for a market at
|
||||
[`/api/v1/jobs/facets`](https://freehire.dev/api/v1/jobs/facets), or narrow it,
|
||||
e.g. `https://freehire.dev/api/v1/jobs/facets?q=react`.
|
||||
[`/api/v1/jobs/facets`](https://freehire.me/api/v1/jobs/facets), or narrow it,
|
||||
e.g. `https://freehire.me/api/v1/jobs/facets?q=react`.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "freehire-cli",
|
||||
"version": "1.0.0",
|
||||
"description": "CLI for searching the freehire.dev job aggregator's public JSON API across many markets (tech-focused) — no authentication, zero runtime dependencies. Base URL is swappable via FREEHIRE_API_URL for self-hosting.",
|
||||
"description": "CLI for searching the freehire.me job aggregator's public JSON API across many markets (tech-focused) — no authentication, zero runtime dependencies. Base URL is swappable via FREEHIRE_API_URL for self-hosting.",
|
||||
"type": "module",
|
||||
"main": "src/cli.ts",
|
||||
"bin": {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#!/usr/bin/env bun
|
||||
// Self-contained CLI for searching the freehire.dev aggregator's public JSON API.
|
||||
// Self-contained CLI for searching the freehire.me aggregator's public JSON API.
|
||||
// No external CLI framework and zero runtime dependencies, so it runs anywhere
|
||||
// `bun` is available with nothing installed beyond the repo clone.
|
||||
//
|
||||
// Hosted-service dependency: reads are public (no API key), but they hit
|
||||
// freehire.dev — a personal project maintained best-effort (no formal SLA). Point
|
||||
// freehire.me — a personal project maintained best-effort (no formal SLA). Point
|
||||
// FREEHIRE_API_URL at a self-hosted freehire backend to swap the source.
|
||||
|
||||
import { runSearch, type SearchOpts } from "./commands/search.js"
|
||||
@@ -69,7 +69,7 @@ function commaList(raw: FlagValue): string[] {
|
||||
.filter(Boolean)
|
||||
}
|
||||
|
||||
const HELP = `freehire-cli — search the freehire.dev job aggregator (many markets, tech-focused)
|
||||
const HELP = `freehire-cli — search the freehire.me job aggregator (many markets, tech-focused)
|
||||
|
||||
USAGE
|
||||
bun run src/cli.ts search [-q "<keywords>"] [facet flags] [--format json|table|plain]
|
||||
@@ -82,7 +82,7 @@ SEARCH FLAGS
|
||||
--limit, -n <n> Results per page (API limit). Default 25.
|
||||
--format <fmt> json (default) | table | plain.
|
||||
|
||||
FACET FILTERS (values from freehire.dev's controlled vocabularies; comma = OR)
|
||||
FACET FILTERS (values from freehire.me's controlled vocabularies; comma = OR)
|
||||
--region <codes> Macro-region: global, eu, us, apac, latam, cis, ... e.g. --region eu,us
|
||||
--country <codes> ISO-3166 alpha-2, e.g. --country DE,GB
|
||||
--city <names> City name(s), e.g. --city Berlin
|
||||
@@ -95,7 +95,7 @@ FACET FILTERS (values from freehire.dev's controlled vocabularies; comma = OR)
|
||||
|
||||
DETAIL
|
||||
<slug|url> A freehire public slug (from a search result's id/slug)
|
||||
or a full https://freehire.dev/jobs/<slug> URL.
|
||||
or a full https://freehire.me/jobs/<slug> URL.
|
||||
|
||||
EXAMPLES
|
||||
bun run src/cli.ts search -q "backend engineer" --seniority senior --limit 10 --format table
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// Data source: the freehire.dev public REST API (JSON, `{data, meta}` envelope).
|
||||
// Data source: the freehire.me public REST API (JSON, `{data, meta}` envelope).
|
||||
// Reads are unauthenticated — no API key, the same bar as linkedin-search — and
|
||||
// unlike the HTML-scraping portals there is no markup to parse: we fetch JSON and
|
||||
// reshape it into the portal-skill contract's result fields. The base URL is
|
||||
// swappable via FREEHIRE_API_URL for self-hosting.
|
||||
|
||||
export const DEFAULT_BASE_URL = "https://freehire.dev"
|
||||
export const DEFAULT_BASE_URL = "https://freehire.me"
|
||||
|
||||
/** API base URL: FREEHIRE_API_URL (for a self-hosted instance) or the default. */
|
||||
export function baseUrl(): string {
|
||||
@@ -16,7 +16,7 @@ export function writeError(error: string, code: string): void {
|
||||
process.stderr.write(JSON.stringify({ error, code }) + "\n")
|
||||
}
|
||||
|
||||
const UA = "freehire-search-skill/1.0 (+https://freehire.dev)"
|
||||
const UA = "freehire-search-skill/1.0 (+https://freehire.me)"
|
||||
|
||||
/** The shared API response envelope: {data, meta, error}. */
|
||||
export interface Envelope<T> {
|
||||
|
||||
@@ -93,7 +93,7 @@ describe("normalizeSlug", () => {
|
||||
expect(normalizeSlug("golang-zensar-2bxu6dxm")).toBe("golang-zensar-2bxu6dxm");
|
||||
});
|
||||
test("extracts the slug from a /jobs/<slug> URL", () => {
|
||||
expect(normalizeSlug("https://freehire.dev/jobs/golang-zensar-2bxu6dxm")).toBe("golang-zensar-2bxu6dxm");
|
||||
expect(normalizeSlug("https://freehire.me/jobs/golang-zensar-2bxu6dxm")).toBe("golang-zensar-2bxu6dxm");
|
||||
});
|
||||
test("rejects a non-slug string", () => {
|
||||
expect(normalizeSlug("not a slug!")).toBeNull();
|
||||
|
||||
Reference in New Issue
Block a user