@ap3x/cadence 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +28 -0
- package/dist/core/backoff.d.ts +21 -0
- package/dist/core/backoff.d.ts.map +1 -0
- package/dist/core/clock.d.ts +48 -0
- package/dist/core/clock.d.ts.map +1 -0
- package/dist/core/engine.d.ts +46 -0
- package/dist/core/engine.d.ts.map +1 -0
- package/dist/core/executor.d.ts +28 -0
- package/dist/core/executor.d.ts.map +1 -0
- package/dist/core/memory-store.d.ts +36 -0
- package/dist/core/memory-store.d.ts.map +1 -0
- package/dist/core/next-run.d.ts +21 -0
- package/dist/core/next-run.d.ts.map +1 -0
- package/dist/core/store.d.ts +52 -0
- package/dist/core/store.d.ts.map +1 -0
- package/dist/core/types.d.ts +116 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/file-store.d.ts +21 -0
- package/dist/file-store.d.ts.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +867 -0
- package/package.json +33 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AP3X
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# @ap3x/cadence
|
|
2
|
+
|
|
3
|
+
A standalone durable scheduler: cron, interval, and one-shot jobs with exactly-once firing semantics and pluggable storage.
|
|
4
|
+
|
|
5
|
+
Part of [AP3X](https://github.com/AP3X-Dev/AP3X) — a TypeScript multi-agent framework.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @ap3x/cadence
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## What's inside
|
|
14
|
+
|
|
15
|
+
- **Schedules** — cron expressions, fixed intervals, and one-shot timers.
|
|
16
|
+
- **Exactly-once** — an occurrence fires once, even across restarts and concurrent workers.
|
|
17
|
+
- **Pluggable stores** — in-memory and file-backed stores ship with the package, behind a store interface with a conformance suite.
|
|
18
|
+
- **Injectable clock** — no wall-clock reads in core, so schedules are testable deterministically.
|
|
19
|
+
|
|
20
|
+
Depends on no other `@ap3x` package.
|
|
21
|
+
|
|
22
|
+
## Documentation
|
|
23
|
+
|
|
24
|
+
See the [AP3X repository](https://github.com/AP3X-Dev/AP3X) for architecture notes, the full package map, and examples.
|
|
25
|
+
|
|
26
|
+
## License
|
|
27
|
+
|
|
28
|
+
MIT
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure, deterministic retry-backoff helpers. No wall-clock reads and no
|
|
3
|
+
* `Math.random` — jitter comes from a deterministic integer hash of a seed the
|
|
4
|
+
* engine derives per-occurrence (e.g. from schedule id + occurrenceAt), so a
|
|
5
|
+
* given (ms, jitterMs, seed) always yields the same value. This keeps retry
|
|
6
|
+
* timing reproducible across restarts and testable under a TestClock.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Exponential backoff: `baseMs * 2^(attempt-1)`, clamped to `capMs`. `attempt`
|
|
10
|
+
* is 1-based; values < 1 are treated as 1. Non-finite inputs are sanitized to
|
|
11
|
+
* keep the result a finite, non-negative number.
|
|
12
|
+
*/
|
|
13
|
+
export declare function backoffMs(attempt: number, baseMs: number, capMs: number): number;
|
|
14
|
+
/**
|
|
15
|
+
* Deterministic jitter. Returns a value in `[ms, ms + jitterMs]` inclusive,
|
|
16
|
+
* derived from `seed` via a mulberry32-style integer hash (two xor-shift +
|
|
17
|
+
* `Math.imul` rounds), so the same `(ms, jitterMs, seed)` is stable. When
|
|
18
|
+
* `jitterMs <= 0` the input `ms` is returned unchanged.
|
|
19
|
+
*/
|
|
20
|
+
export declare function applyJitter(ms: number, jitterMs: number, seed: number): number;
|
|
21
|
+
//# sourceMappingURL=backoff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backoff.d.ts","sourceRoot":"","sources":["../../src/core/backoff.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAMhF;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAU9E"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `Clock` port: the only way cadence reads time or waits.
|
|
3
|
+
*
|
|
4
|
+
* Core code never touches the wall clock directly — a guard test bans argless
|
|
5
|
+
* wall-clock and RNG reads across all of `src/`. Time enters through an
|
|
6
|
+
* injected `Clock`, which keeps the engine deterministic under test.
|
|
7
|
+
*
|
|
8
|
+
* - `SystemClock` wraps the real clock, but takes `nowFn` as a REQUIRED
|
|
9
|
+
* constructor argument so this file never contains a wall-clock literal. The
|
|
10
|
+
* AP3X CLI boundary (outside `src/`) constructs it by injecting a wall-clock
|
|
11
|
+
* factory. `sleep` is `setTimeout`-based.
|
|
12
|
+
* - `TestClock` does pure arithmetic on an injected start instant — no
|
|
13
|
+
* wall-clock at all. `sleep` resolves only when `advance`/`setNow` push
|
|
14
|
+
* `now()` past the sleep's absolute deadline, so time is fully driven by the
|
|
15
|
+
* test.
|
|
16
|
+
*
|
|
17
|
+
* Abort semantics: `sleep(ms, signal)` RESOLVES (does not reject) when the
|
|
18
|
+
* signal aborts. The daemon tick loop passes its abort signal to `sleep`
|
|
19
|
+
* between ticks; resolving on abort lets the loop fall through and exit
|
|
20
|
+
* promptly rather than having to catch a rejection.
|
|
21
|
+
*/
|
|
22
|
+
export interface Clock {
|
|
23
|
+
now(): Date;
|
|
24
|
+
sleep(ms: number, signal?: AbortSignal): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
/** A real clock. `nowFn` is injected so this file holds no wall-clock literal. */
|
|
27
|
+
export declare class SystemClock implements Clock {
|
|
28
|
+
#private;
|
|
29
|
+
constructor(nowFn: () => Date);
|
|
30
|
+
now(): Date;
|
|
31
|
+
sleep(ms: number, signal?: AbortSignal): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A deterministic clock whose time only moves via `advance`/`setNow`. Pending
|
|
35
|
+
* sleeps are tracked by absolute deadline and resolved, in deadline order, as
|
|
36
|
+
* soon as `now()` reaches them.
|
|
37
|
+
*/
|
|
38
|
+
export declare class TestClock implements Clock {
|
|
39
|
+
#private;
|
|
40
|
+
constructor(startIso: string);
|
|
41
|
+
now(): Date;
|
|
42
|
+
/** Move time forward by `ms`, resolving any sleeps whose deadline passed. */
|
|
43
|
+
advance(ms: number): void;
|
|
44
|
+
/** Jump to an absolute instant, resolving any sleeps whose deadline passed. */
|
|
45
|
+
setNow(iso: string): void;
|
|
46
|
+
sleep(ms: number, signal?: AbortSignal): Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=clock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clock.d.ts","sourceRoot":"","sources":["../../src/core/clock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,KAAK;IACpB,GAAG,IAAI,IAAI,CAAC;IACZ,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxD;AAED,kFAAkF;AAClF,qBAAa,WAAY,YAAW,KAAK;;gBAG3B,KAAK,EAAE,MAAM,IAAI;IAI7B,GAAG,IAAI,IAAI;IAIX,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAcvD;AAOD;;;;GAIG;AACH,qBAAa,SAAU,YAAW,KAAK;;gBAIzB,QAAQ,EAAE,MAAM;IAI5B,GAAG,IAAI,IAAI;IAIX,6EAA6E;IAC7E,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAKzB,+EAA+E;IAC/E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAKzB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAwBvD"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Clock } from "./clock";
|
|
2
|
+
import type { Executor } from "./executor";
|
|
3
|
+
import type { Store } from "./store";
|
|
4
|
+
import { type Attempt, type NewSchedule, type Schedule } from "./types";
|
|
5
|
+
export interface EngineOptions {
|
|
6
|
+
store: Store;
|
|
7
|
+
executor: Executor;
|
|
8
|
+
clock: Clock;
|
|
9
|
+
/** Poll-loop cadence. Default 1000ms. */
|
|
10
|
+
pollIntervalMs?: number;
|
|
11
|
+
/** Max occurrences claimed (and retries picked up) per tick. Default 25. */
|
|
12
|
+
batchLimit?: number;
|
|
13
|
+
/** Age past which a "running" attempt counts as a crashed worker. Default 5min. */
|
|
14
|
+
orphanGraceMs?: number;
|
|
15
|
+
/** Retry backoff ladder base. Default 1000ms. */
|
|
16
|
+
retryBaseMs?: number;
|
|
17
|
+
/** Retry backoff ladder cap. Default 60s. */
|
|
18
|
+
retryCapMs?: number;
|
|
19
|
+
/** Id source for schedules and attempts. Default: per-engine counter. */
|
|
20
|
+
idFactory?: () => string;
|
|
21
|
+
}
|
|
22
|
+
export declare class Engine {
|
|
23
|
+
#private;
|
|
24
|
+
constructor(opts: EngineOptions);
|
|
25
|
+
/**
|
|
26
|
+
* Validate (TypeBox shape + kind-specific expression check), fill server-side
|
|
27
|
+
* fields, compute the initial slot, and persist. Throws on invalid input.
|
|
28
|
+
*/
|
|
29
|
+
register(input: NewSchedule): Promise<Schedule>;
|
|
30
|
+
remove(id: string): Promise<boolean>;
|
|
31
|
+
setEnabled(id: string, enabled: boolean): Promise<void>;
|
|
32
|
+
get(id: string): Promise<Schedule | undefined>;
|
|
33
|
+
list(): Promise<Schedule[]>;
|
|
34
|
+
/** Attempt history for one schedule, newest first — "did it actually run?". */
|
|
35
|
+
listAttempts(scheduleId: string, limit?: number): Promise<Attempt[]>;
|
|
36
|
+
/** Occurrences that exhausted the retry ladder: the permanent-failure record. */
|
|
37
|
+
deadLetteredFor(scheduleId: string): Promise<Attempt[]>;
|
|
38
|
+
/** Begin the poll loop. Idempotent: a second start while running is a no-op. */
|
|
39
|
+
start(): void;
|
|
40
|
+
/**
|
|
41
|
+
* Drain: stop claiming, let in-flight attempts run to completion (bounded by
|
|
42
|
+
* their own maxRuntimeMs timeouts), then resolve. Idempotent.
|
|
43
|
+
*/
|
|
44
|
+
stop(): Promise<void>;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/core/engine.ts"],"names":[],"mappings":"AA+CA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAoB,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE7D,OAAO,KAAK,EAAqB,KAAK,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,WAAW,EAAqB,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE3F,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,yCAAyC;IACzC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,MAAM,CAAC;CAC1B;AAED,qBAAa,MAAM;;gBAmBL,IAAI,EAAE,aAAa;IAc/B;;;OAGG;IACG,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;IA6BrD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIpC,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvD,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IAI9C,IAAI,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAI3B,+EAA+E;IAC/E,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAIhE,iFAAiF;IACjF,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAMvD,gFAAgF;IAChF,KAAK,IAAI,IAAI;IAOb;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CA+Q5B"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Executor port: what a schedule fire actually *does*. The engine owns the
|
|
3
|
+
* WHEN (due computation, exactly-once, retry, timeout); the Executor owns the
|
|
4
|
+
* WHAT. Concrete executors (e.g. an AgentBackend-backed one) live outside
|
|
5
|
+
* `src/core`, which keeps the core free of AP3X imports and extractable as a
|
|
6
|
+
* standalone package.
|
|
7
|
+
*/
|
|
8
|
+
import type { Schedule } from "./types";
|
|
9
|
+
/** Everything an executor needs for a single attempt of one occurrence. */
|
|
10
|
+
export interface ExecutionContext {
|
|
11
|
+
schedule: Schedule;
|
|
12
|
+
/** The occurrence instant this attempt belongs to (ISO-8601). */
|
|
13
|
+
occurrenceAt: string;
|
|
14
|
+
/** 1-based attempt number within the retry ladder. */
|
|
15
|
+
attempt: number;
|
|
16
|
+
/** Aborted by the engine on timeout, shutdown, or kill-switch. */
|
|
17
|
+
signal: AbortSignal;
|
|
18
|
+
}
|
|
19
|
+
/** The result of one execution attempt. */
|
|
20
|
+
export interface ExecutionOutcome {
|
|
21
|
+
ok: boolean;
|
|
22
|
+
error?: string;
|
|
23
|
+
result?: unknown;
|
|
24
|
+
}
|
|
25
|
+
export interface Executor {
|
|
26
|
+
execute(ctx: ExecutionContext): Promise<ExecutionOutcome>;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/core/executor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,2EAA2E;AAC3E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,QAAQ,CAAC;IACnB,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAC;IACrB,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,2CAA2C;AAC3C,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC3D"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory reference {@link Store}. Backs schedules and attempts with `Map`s.
|
|
3
|
+
*
|
|
4
|
+
* The atomic-claim contract is modeled by a single-writer, in-process critical
|
|
5
|
+
* section: JavaScript's run-to-completion means each `claimDue` call executes
|
|
6
|
+
* without interleaving, and claimed slots are stamped into a `#claimed` set so a
|
|
7
|
+
* second `claimDue` at the same instant (before `advanceSlot`) can never
|
|
8
|
+
* re-return the same occurrence. `advanceSlot` clears the claim as it persists
|
|
9
|
+
* the next slot. This is what makes firing exactly-once.
|
|
10
|
+
*
|
|
11
|
+
* ponytail: single global in-process claim. FileStore keeps the same in-process
|
|
12
|
+
* contract (one engine process per store directory — no lockfile); a true
|
|
13
|
+
* multi-process store (e.g. Postgres) would enforce it with a row lock.
|
|
14
|
+
*/
|
|
15
|
+
import type { Clock } from "./clock";
|
|
16
|
+
import type { ClaimedOccurrence, Store } from "./store";
|
|
17
|
+
import type { Attempt, Schedule } from "./types";
|
|
18
|
+
export declare class InMemoryStore implements Store {
|
|
19
|
+
#private;
|
|
20
|
+
constructor(clock: Clock);
|
|
21
|
+
createSchedule(s: Schedule): Promise<void>;
|
|
22
|
+
getSchedule(id: string): Promise<Schedule | undefined>;
|
|
23
|
+
listSchedules(): Promise<Schedule[]>;
|
|
24
|
+
removeSchedule(id: string): Promise<boolean>;
|
|
25
|
+
setEnabled(id: string, enabled: boolean): Promise<void>;
|
|
26
|
+
claimDue(now: Date, limit: number): Promise<ClaimedOccurrence[]>;
|
|
27
|
+
advanceSlot(id: string, nextRunAt: string | null, lastTriggeredAt: string, occurrenceCount: number): Promise<void>;
|
|
28
|
+
openAttempt(a: Attempt): Promise<void>;
|
|
29
|
+
updateAttempt(id: string, patch: Partial<Attempt>): Promise<void>;
|
|
30
|
+
listDueRetries(now: Date, limit: number): Promise<Attempt[]>;
|
|
31
|
+
hasActiveAttempt(scheduleId: string): Promise<boolean>;
|
|
32
|
+
reclaimOrphans(now: Date, graceMs: number): Promise<Attempt[]>;
|
|
33
|
+
listAttempts(scheduleId: string, limit: number): Promise<Attempt[]>;
|
|
34
|
+
deadLetteredFor(scheduleId: string): Promise<Attempt[]>;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=memory-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-store.d.ts","sourceRoot":"","sources":["../../src/core/memory-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEjD,qBAAa,aAAc,YAAW,KAAK;;gBAQ7B,KAAK,EAAE,KAAK;IAIlB,cAAc,CAAC,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1C,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IAKtD,aAAa,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAIpC,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK5C,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvD,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAchE,WAAW,CACf,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,eAAe,EAAE,MAAM,EACvB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC;IAUV,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAItC,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjE,cAAc,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAa5D,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAItD,cAAc,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAY9D,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IASnE,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;CAK9D"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { NewSchedule, Schedule } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* The next fire instant strictly AFTER `after`, or `null` if none exists
|
|
4
|
+
* (a malformed expression, a past one-shot, or an expired schedule).
|
|
5
|
+
*/
|
|
6
|
+
export declare function computeNextRun(s: Pick<Schedule, "kind" | "expr" | "timezone">, after: Date): Date | null;
|
|
7
|
+
/**
|
|
8
|
+
* Validate a registration input: syntactically valid + reachable for its kind,
|
|
9
|
+
* and — when `opts.minCadenceMs` is set — not tighter than the anti-runaway floor.
|
|
10
|
+
*
|
|
11
|
+
* A past one-shot is NOT an error: it is a valid schedule that simply will not fire.
|
|
12
|
+
*/
|
|
13
|
+
export declare function validateSchedule(input: NewSchedule, opts?: {
|
|
14
|
+
minCadenceMs?: number;
|
|
15
|
+
}): {
|
|
16
|
+
ok: true;
|
|
17
|
+
} | {
|
|
18
|
+
ok: false;
|
|
19
|
+
error: string;
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=next-run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"next-run.d.ts","sourceRoot":"","sources":["../../src/core/next-run.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAKrD;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC,EAC/C,KAAK,EAAE,IAAI,GACV,IAAI,GAAG,IAAI,CAwBb;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,WAAW,EAClB,IAAI,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAO,GACnC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAuD7C"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The durable-persistence port every cadence adapter implements
|
|
3
|
+
* (in-memory, file, Postgres, HTTP). The engine depends only on this
|
|
4
|
+
* interface, never on a concrete store.
|
|
5
|
+
*/
|
|
6
|
+
import type { Attempt, Schedule } from "./types";
|
|
7
|
+
/** A schedule whose due slot has been claimed for firing, at a fixed instant. */
|
|
8
|
+
export interface ClaimedOccurrence {
|
|
9
|
+
schedule: Schedule;
|
|
10
|
+
occurrenceAt: string;
|
|
11
|
+
}
|
|
12
|
+
export interface Store {
|
|
13
|
+
createSchedule(s: Schedule): Promise<void>;
|
|
14
|
+
getSchedule(id: string): Promise<Schedule | undefined>;
|
|
15
|
+
listSchedules(): Promise<Schedule[]>;
|
|
16
|
+
removeSchedule(id: string): Promise<boolean>;
|
|
17
|
+
setEnabled(id: string, enabled: boolean): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* ATOMIC claim. Select due (`nextRunAt <= now`) AND enabled schedules and mark
|
|
20
|
+
* their slot claimed in one critical section, so no concurrent caller can take
|
|
21
|
+
* the same occurrence. Returns the claimed occurrences. This exclusivity is
|
|
22
|
+
* half of what makes firing exactly-once — {@link Store.advanceSlot} is the
|
|
23
|
+
* other half and MUST run in the same logical transaction/critical section.
|
|
24
|
+
*/
|
|
25
|
+
claimDue(now: Date, limit: number): Promise<ClaimedOccurrence[]>;
|
|
26
|
+
/**
|
|
27
|
+
* Persist the next occurrence + lastTriggered + occurrenceCount in the SAME
|
|
28
|
+
* logical transaction/critical-section as the {@link Store.claimDue} that
|
|
29
|
+
* produced this slot. Committing the claim and the slot advance together is
|
|
30
|
+
* what guarantees each occurrence fires exactly once, even under concurrent
|
|
31
|
+
* or crashed workers.
|
|
32
|
+
*/
|
|
33
|
+
advanceSlot(id: string, nextRunAt: string | null, lastTriggeredAt: string, occurrenceCount: number): Promise<void>;
|
|
34
|
+
openAttempt(a: Attempt): Promise<void>;
|
|
35
|
+
updateAttempt(id: string, patch: Partial<Attempt>): Promise<void>;
|
|
36
|
+
/** Attempts with status "pending" and `retryAt <= now`. */
|
|
37
|
+
listDueRetries(now: Date, limit: number): Promise<Attempt[]>;
|
|
38
|
+
/** Whether the schedule has any attempt currently in status "running". */
|
|
39
|
+
hasActiveAttempt(scheduleId: string): Promise<boolean>;
|
|
40
|
+
/** "running" attempts whose `startedAt` is older than `graceMs` (crashed workers). */
|
|
41
|
+
reclaimOrphans(now: Date, graceMs: number): Promise<Attempt[]>;
|
|
42
|
+
/** Attempt history for a schedule, newest-first (audit/history). */
|
|
43
|
+
listAttempts(scheduleId: string, limit: number): Promise<Attempt[]>;
|
|
44
|
+
/** Attempts with status "dead_letter" (for replay). */
|
|
45
|
+
deadLetteredFor(scheduleId: string): Promise<Attempt[]>;
|
|
46
|
+
}
|
|
47
|
+
/** Error raised by store adapters for the well-known failure modes. */
|
|
48
|
+
export declare class StoreError extends Error {
|
|
49
|
+
readonly code: "not_found" | "conflict" | "locked" | "corrupt";
|
|
50
|
+
constructor(code: "not_found" | "conflict" | "locked" | "corrupt", message: string);
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/core/store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEjD,iFAAiF;AACjF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,KAAK;IACpB,cAAc,CAAC,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC;IACvD,aAAa,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IACrC,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAExD;;;;;;OAMG;IACH,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAEjE;;;;;;OAMG;IACH,WAAW,CACT,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,eAAe,EAAE,MAAM,EACvB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAElE,2DAA2D;IAC3D,cAAc,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAC7D,0EAA0E;IAC1E,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD,sFAAsF;IACtF,cAAc,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/D,oEAAoE;IACpE,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACpE,uDAAuD;IACvD,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;CACzD;AAED,uEAAuE;AACvE,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC;gBAEnD,IAAI,EAAE,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM;CAKnF"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/** The three schedule kinds cadence knows how to compute a next run for. */
|
|
2
|
+
export declare const ScheduleKind: {
|
|
3
|
+
readonly Cron: "cron";
|
|
4
|
+
readonly Interval: "interval";
|
|
5
|
+
readonly OneShot: "one_shot";
|
|
6
|
+
};
|
|
7
|
+
export type ScheduleKind = (typeof ScheduleKind)[keyof typeof ScheduleKind];
|
|
8
|
+
/** What to do when a new occurrence is due while a prior attempt still runs. */
|
|
9
|
+
export type OverlapPolicy = "allow" | "skip_if_running" | "queue";
|
|
10
|
+
/** What to do with occurrences missed while the engine was down. */
|
|
11
|
+
export type MisfirePolicy = "fire" | "skip" | "backfill";
|
|
12
|
+
/** Lifecycle state of a single execution attempt. */
|
|
13
|
+
export type AttemptStatus = "running" | "succeeded" | "failed" | "pending" | "dead_letter";
|
|
14
|
+
export interface Schedule {
|
|
15
|
+
id: string;
|
|
16
|
+
name?: string;
|
|
17
|
+
kind: ScheduleKind;
|
|
18
|
+
expr: string;
|
|
19
|
+
timezone: string;
|
|
20
|
+
payload: unknown;
|
|
21
|
+
enabled: boolean;
|
|
22
|
+
overlap: OverlapPolicy;
|
|
23
|
+
misfire: MisfirePolicy;
|
|
24
|
+
maxAttempts: number;
|
|
25
|
+
maxRuntimeMs?: number;
|
|
26
|
+
jitterMs?: number;
|
|
27
|
+
validFrom?: string;
|
|
28
|
+
validUntil?: string;
|
|
29
|
+
maxOccurrences?: number;
|
|
30
|
+
occurrenceCount: number;
|
|
31
|
+
nextRunAt: string | null;
|
|
32
|
+
lastTriggeredAt?: string;
|
|
33
|
+
createdAt: string;
|
|
34
|
+
metadata?: Record<string, unknown>;
|
|
35
|
+
}
|
|
36
|
+
export declare const ScheduleSchema: import("@sinclair/typebox").TObject<{
|
|
37
|
+
id: import("@sinclair/typebox").TString;
|
|
38
|
+
name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
39
|
+
kind: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"cron">, import("@sinclair/typebox").TLiteral<"interval">, import("@sinclair/typebox").TLiteral<"one_shot">]>;
|
|
40
|
+
expr: import("@sinclair/typebox").TString;
|
|
41
|
+
timezone: import("@sinclair/typebox").TString;
|
|
42
|
+
payload: import("@sinclair/typebox").TUnknown;
|
|
43
|
+
enabled: import("@sinclair/typebox").TBoolean;
|
|
44
|
+
overlap: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"allow">, import("@sinclair/typebox").TLiteral<"skip_if_running">, import("@sinclair/typebox").TLiteral<"queue">]>;
|
|
45
|
+
misfire: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"fire">, import("@sinclair/typebox").TLiteral<"skip">, import("@sinclair/typebox").TLiteral<"backfill">]>;
|
|
46
|
+
maxAttempts: import("@sinclair/typebox").TNumber;
|
|
47
|
+
maxRuntimeMs: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
48
|
+
jitterMs: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
49
|
+
validFrom: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
50
|
+
validUntil: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
51
|
+
maxOccurrences: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
52
|
+
occurrenceCount: import("@sinclair/typebox").TNumber;
|
|
53
|
+
nextRunAt: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TNull]>;
|
|
54
|
+
lastTriggeredAt: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
55
|
+
createdAt: import("@sinclair/typebox").TString;
|
|
56
|
+
metadata: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TUnknown>>;
|
|
57
|
+
}>;
|
|
58
|
+
export interface Attempt {
|
|
59
|
+
id: string;
|
|
60
|
+
scheduleId: string;
|
|
61
|
+
occurrenceAt: string;
|
|
62
|
+
attempt: number;
|
|
63
|
+
status: AttemptStatus;
|
|
64
|
+
startedAt?: string;
|
|
65
|
+
finishedAt?: string;
|
|
66
|
+
retryAt?: string;
|
|
67
|
+
error?: string;
|
|
68
|
+
outcome?: unknown;
|
|
69
|
+
}
|
|
70
|
+
export declare const AttemptSchema: import("@sinclair/typebox").TObject<{
|
|
71
|
+
id: import("@sinclair/typebox").TString;
|
|
72
|
+
scheduleId: import("@sinclair/typebox").TString;
|
|
73
|
+
occurrenceAt: import("@sinclair/typebox").TString;
|
|
74
|
+
attempt: import("@sinclair/typebox").TNumber;
|
|
75
|
+
status: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"running">, import("@sinclair/typebox").TLiteral<"succeeded">, import("@sinclair/typebox").TLiteral<"failed">, import("@sinclair/typebox").TLiteral<"pending">, import("@sinclair/typebox").TLiteral<"dead_letter">]>;
|
|
76
|
+
startedAt: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
77
|
+
finishedAt: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
78
|
+
retryAt: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
79
|
+
error: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
80
|
+
outcome: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnknown>;
|
|
81
|
+
}>;
|
|
82
|
+
export interface NewSchedule {
|
|
83
|
+
name?: string;
|
|
84
|
+
kind: ScheduleKind;
|
|
85
|
+
expr: string;
|
|
86
|
+
timezone?: string;
|
|
87
|
+
payload: unknown;
|
|
88
|
+
overlap?: OverlapPolicy;
|
|
89
|
+
misfire?: MisfirePolicy;
|
|
90
|
+
maxAttempts?: number;
|
|
91
|
+
maxRuntimeMs?: number;
|
|
92
|
+
jitterMs?: number;
|
|
93
|
+
validFrom?: string;
|
|
94
|
+
validUntil?: string;
|
|
95
|
+
maxOccurrences?: number;
|
|
96
|
+
enabled?: boolean;
|
|
97
|
+
metadata?: Record<string, unknown>;
|
|
98
|
+
}
|
|
99
|
+
export declare const NewScheduleSchema: import("@sinclair/typebox").TObject<{
|
|
100
|
+
name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
101
|
+
kind: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"cron">, import("@sinclair/typebox").TLiteral<"interval">, import("@sinclair/typebox").TLiteral<"one_shot">]>;
|
|
102
|
+
expr: import("@sinclair/typebox").TString;
|
|
103
|
+
timezone: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
104
|
+
payload: import("@sinclair/typebox").TUnknown;
|
|
105
|
+
overlap: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"allow">, import("@sinclair/typebox").TLiteral<"skip_if_running">, import("@sinclair/typebox").TLiteral<"queue">]>>;
|
|
106
|
+
misfire: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"fire">, import("@sinclair/typebox").TLiteral<"skip">, import("@sinclair/typebox").TLiteral<"backfill">]>>;
|
|
107
|
+
maxAttempts: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
108
|
+
maxRuntimeMs: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
109
|
+
jitterMs: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
110
|
+
validFrom: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
111
|
+
validUntil: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
112
|
+
maxOccurrences: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
113
|
+
enabled: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
114
|
+
metadata: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TUnknown>>;
|
|
115
|
+
}>;
|
|
116
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAcA,4EAA4E;AAC5E,eAAO,MAAM,YAAY;;;;CAIf,CAAC;AACX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAE5E,gFAAgF;AAChF,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,iBAAiB,GAAG,OAAO,CAAC;AAElE,oEAAoE;AACpE,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC;AAEzD,qDAAqD;AACrD,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,aAAa,CAAC;AAmC3F,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;EAqBzB,CAAC;AAMH,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,eAAO,MAAM,aAAa;;;;;;;;;;;EAWxB,CAAC;AAMH,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;EAgB5B,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ClaimedOccurrence, type Store } from "./core/store";
|
|
2
|
+
import { type Attempt, type Schedule } from "./core/types";
|
|
3
|
+
export declare class FileStore implements Store {
|
|
4
|
+
#private;
|
|
5
|
+
constructor(dir: string);
|
|
6
|
+
createSchedule(s: Schedule): Promise<void>;
|
|
7
|
+
getSchedule(id: string): Promise<Schedule | undefined>;
|
|
8
|
+
listSchedules(): Promise<Schedule[]>;
|
|
9
|
+
removeSchedule(id: string): Promise<boolean>;
|
|
10
|
+
setEnabled(id: string, enabled: boolean): Promise<void>;
|
|
11
|
+
claimDue(now: Date, limit: number): Promise<ClaimedOccurrence[]>;
|
|
12
|
+
advanceSlot(id: string, nextRunAt: string | null, lastTriggeredAt: string, occurrenceCount: number): Promise<void>;
|
|
13
|
+
openAttempt(a: Attempt): Promise<void>;
|
|
14
|
+
updateAttempt(id: string, patch: Partial<Attempt>): Promise<void>;
|
|
15
|
+
listDueRetries(now: Date, limit: number): Promise<Attempt[]>;
|
|
16
|
+
hasActiveAttempt(scheduleId: string): Promise<boolean>;
|
|
17
|
+
reclaimOrphans(now: Date, graceMs: number): Promise<Attempt[]>;
|
|
18
|
+
listAttempts(scheduleId: string, limit: number): Promise<Attempt[]>;
|
|
19
|
+
deadLetteredFor(scheduleId: string): Promise<Attempt[]>;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=file-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-store.d.ts","sourceRoot":"","sources":["../src/file-store.ts"],"names":[],"mappings":"AAuCA,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,KAAK,EAAc,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,KAAK,OAAO,EAAiB,KAAK,QAAQ,EAAkB,MAAM,cAAc,CAAC;AAK1F,qBAAa,SAAU,YAAW,KAAK;;gBASzB,GAAG,EAAE,MAAM;IAyDjB,cAAc,CAAC,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAK1C,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IAKtD,aAAa,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAIpC,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAO5C,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAQvD,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAchE,WAAW,CACf,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,eAAe,EAAE,MAAM,EACvB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC;IAWV,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAKtC,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAQjE,cAAc,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAa5D,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAItD,cAAc,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAY9D,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IASnE,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;CAK9D"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from "./core/backoff";
|
|
2
|
+
export * from "./core/clock";
|
|
3
|
+
export * from "./core/engine";
|
|
4
|
+
export * from "./core/executor";
|
|
5
|
+
export * from "./core/memory-store";
|
|
6
|
+
export * from "./core/next-run";
|
|
7
|
+
export * from "./core/store";
|
|
8
|
+
export * from "./core/types";
|
|
9
|
+
export * from "./file-store";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC"}
|