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:
Ilya Strelov
2026-07-23 10:17:10 +02:00
committed by GitHub
parent 7db231c680
commit 1ae66ad094
8 changed files with 28 additions and 28 deletions
+6 -6
View File
@@ -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();