# job-registry _(no submodules)_ ## Purpose Provides a string-to-jobId binding so application code can refer to scheduled jobs by stable name (`"nightly-cleanup"`, `"hourly-report"`) without leaking the scheduler's internal id generator (`crypto.randomUUID()` by default). The registry is a thin `Map` wrapper with explicit semantics for duplicate names — it throws rather than silently overwriting, because silent overwrite has been a recurring source of "ghost job" bugs in similar systems where a redeploy registers the same name twice and the original job leaks. ## Features - `register(name, jobId)` — throws on duplicate name with a typed `JobSchedulerError`. - `unregister(name)` — returns boolean for unambiguous removal semantics. - `resolve(name) -> jobId | undefined` — pure lookup, never throws. - `list()` — frozen snapshot for diagnostics and admin endpoints. - Zero dependencies beyond the package's own error class. ## Usage: Basic Example ```ts import { JobRegistry } from "@suaveplan/job-scheduler"; const registry = new JobRegistry(); registry.register("nightly", "uuid-1"); console.log(registry.resolve("nightly")); // "uuid-1" registry.unregister("nightly"); ``` ## Usage: Advanced Example ```ts import { createJobScheduler, JobRegistry, JobSchedulerError, JOB_SCHEDULER_CODES, } from "@suaveplan/job-scheduler"; const scheduler = createJobScheduler(); const registry = new JobRegistry(); const jobId = scheduler.schedule("0 * * * *", async () => { // ... }); registry.register("hourly-report", jobId); try { registry.register("hourly-report", "different-id"); } catch (err) { if ( err instanceof JobSchedulerError && err.code === JOB_SCHEDULER_CODES.JOB_NOT_FOUND ) { // Duplicate-name guard tripped — surface a CLI-friendly message. } } for (const { name, jobId } of registry.list()) { console.log(name, "->", jobId); } ``` ## API Reference - `class JobRegistry` - `register(name: string, jobId: string): void` — throws `JobSchedulerError` on duplicate name. - `unregister(name: string): boolean` — `true` when removed, `false` when unknown. - `resolve(name: string): string | undefined` — pure lookup. - `list(): ReadonlyArray<{ name: string; jobId: string }>` — frozen snapshot. ## Implementation Notes The duplicate-name branch reuses `JOB_SCHEDULER.JOB_NOT_FOUND` rather than introducing a fourth registry code. The decision is deliberate: the registry is a 12-line wrapper over `Map`, and growing the error registry just for it would couple the package's public contract to a peripheral feature. The `context` payload on the thrown error includes the conflicting `name`, so consumers branching on the duplicate-name case can recognise it without ambiguity. The registry is not synchronised — concurrent registration from two async tasks may race; if you need atomicity, wrap it in a `Mutex` from `@suaveplan/timing`.