first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
# job-registry
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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`.