@cronwatch/sdk 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/README.md +69 -0
- package/dist/anthropic.cjs +84 -0
- package/dist/anthropic.cjs.map +1 -0
- package/dist/anthropic.d.cts +35 -0
- package/dist/anthropic.d.ts +35 -0
- package/dist/anthropic.js +78 -0
- package/dist/anthropic.js.map +1 -0
- package/dist/discord.cjs +42 -0
- package/dist/discord.cjs.map +1 -0
- package/dist/discord.d.cts +11 -0
- package/dist/discord.d.ts +11 -0
- package/dist/discord.js +40 -0
- package/dist/discord.js.map +1 -0
- package/dist/index.cjs +1317 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +219 -0
- package/dist/index.d.ts +219 -0
- package/dist/index.js +1302 -0
- package/dist/index.js.map +1 -0
- package/dist/postgres.cjs +142 -0
- package/dist/postgres.cjs.map +1 -0
- package/dist/postgres.d.cts +19 -0
- package/dist/postgres.d.ts +19 -0
- package/dist/postgres.js +136 -0
- package/dist/postgres.js.map +1 -0
- package/dist/slack.cjs +44 -0
- package/dist/slack.cjs.map +1 -0
- package/dist/slack.d.cts +12 -0
- package/dist/slack.d.ts +12 -0
- package/dist/slack.js +42 -0
- package/dist/slack.js.map +1 -0
- package/dist/sqlite.cjs +151 -0
- package/dist/sqlite.cjs.map +1 -0
- package/dist/sqlite.d.cts +17 -0
- package/dist/sqlite.d.ts +17 -0
- package/dist/sqlite.js +144 -0
- package/dist/sqlite.js.map +1 -0
- package/dist/types-BQ1P8z55.d.cts +159 -0
- package/dist/types-BQ1P8z55.d.ts +159 -0
- package/dist/webhook.cjs +24 -0
- package/dist/webhook.cjs.map +1 -0
- package/dist/webhook.d.cts +20 -0
- package/dist/webhook.d.ts +20 -0
- package/dist/webhook.js +22 -0
- package/dist/webhook.js.map +1 -0
- package/package.json +114 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { S as Store, a as AlertChannel, T as TriageFn, D as Duration, J as JobOptions, b as JobDefinition, R as Run, C as CheckResult, c as JobSummary, d as JobState, A as Alert, e as Condition, f as StoredJobDefinition } from './types-BQ1P8z55.js';
|
|
2
|
+
export { g as AlertType, E as ExpectRule, h as JobHealth, i as RunStatus, j as StoredJob, k as TriageContext } from './types-BQ1P8z55.js';
|
|
3
|
+
import { Cron } from 'croner';
|
|
4
|
+
|
|
5
|
+
/** What a job function receives. */
|
|
6
|
+
interface JobContext {
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly runId: string;
|
|
9
|
+
readonly startedAt: number;
|
|
10
|
+
/** Aborts when the job's timeout elapses. Honour it if the work can stop. */
|
|
11
|
+
readonly signal: AbortSignal;
|
|
12
|
+
/** Append a line of output. Kept with the run, capped at 16 KB, shown in alerts and the dashboard. */
|
|
13
|
+
log(...parts: unknown[]): void;
|
|
14
|
+
/** Report a number for this run: tokens, cost, rows, anything. Watched against budgets and baselines. */
|
|
15
|
+
metric(name: string, value: number): void;
|
|
16
|
+
metrics(values: Record<string, number>): void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface RoutesOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Required to reach anything. Send it as `Authorization: Bearer <token>`,
|
|
22
|
+
* or open the dashboard once with `?token=<token>` and a cookie is set.
|
|
23
|
+
* Defaults to process.env.CRONWATCH_TOKEN. With no token at all, the routes
|
|
24
|
+
* are open in development and refuse to serve in production.
|
|
25
|
+
*
|
|
26
|
+
* The check endpoint (/api/check) also accepts the client's cronSecret, so
|
|
27
|
+
* a platform cron that sends `Authorization: Bearer <CRON_SECRET>` can
|
|
28
|
+
* trigger checks without knowing the dashboard token.
|
|
29
|
+
*/
|
|
30
|
+
token?: string | null;
|
|
31
|
+
/** Where the routes are mounted, so links resolve. Default "/cronwatch". */
|
|
32
|
+
basePath?: string;
|
|
33
|
+
}
|
|
34
|
+
type FetchHandler = (request: Request) => Promise<Response>;
|
|
35
|
+
interface Routes {
|
|
36
|
+
handler: FetchHandler;
|
|
37
|
+
GET: FetchHandler;
|
|
38
|
+
POST: FetchHandler;
|
|
39
|
+
DELETE: FetchHandler;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A fetch-style handler serving the dashboard and a small JSON API. Mount it
|
|
43
|
+
* in a Next.js app at app/cronwatch/[[...path]]/route.ts:
|
|
44
|
+
*
|
|
45
|
+
* export const { GET, POST, DELETE } = cw.routes();
|
|
46
|
+
*/
|
|
47
|
+
declare function createRoutes(cw: CronWatch, options?: RoutesOptions): Routes;
|
|
48
|
+
|
|
49
|
+
type JobFn<T> = (job: JobContext) => Promise<T> | T;
|
|
50
|
+
type HandlerFn<T> = (job: JobContext, request: Request) => Promise<T> | T;
|
|
51
|
+
interface HandlerOptions {
|
|
52
|
+
/**
|
|
53
|
+
* Callers must send `Authorization: Bearer <secret>`. Defaults to the
|
|
54
|
+
* client's cronSecret, which defaults to process.env.CRON_SECRET (what
|
|
55
|
+
* Vercel sends its cron requests with). Pass null to allow anyone.
|
|
56
|
+
*/
|
|
57
|
+
secret?: string | null;
|
|
58
|
+
}
|
|
59
|
+
interface JobHandle {
|
|
60
|
+
readonly name: string;
|
|
61
|
+
readonly definition: JobDefinition;
|
|
62
|
+
/** Run the function now, recording the run. Rethrows whatever the function throws. */
|
|
63
|
+
run<T>(fn: JobFn<T>, options?: {
|
|
64
|
+
trigger?: string;
|
|
65
|
+
}): Promise<T>;
|
|
66
|
+
/** A fetch-style request handler (Next.js route, Hono, Bun, Deno) that runs the function and records the run. */
|
|
67
|
+
handler<T>(fn: HandlerFn<T>, options?: HandlerOptions): (request: Request) => Promise<Response>;
|
|
68
|
+
}
|
|
69
|
+
interface CronWatchOptions {
|
|
70
|
+
/** Where jobs, runs and state live. Defaults to an in-memory store that forgets on restart. */
|
|
71
|
+
store?: Store;
|
|
72
|
+
/** Where alerts go. Defaults to the console. */
|
|
73
|
+
alerts?: AlertChannel[];
|
|
74
|
+
/** Adds a short diagnosis to failure alerts. See @cronwatch/sdk/anthropic. */
|
|
75
|
+
triage?: TriageFn;
|
|
76
|
+
/** Shared secret that handler() requests must carry. Defaults to process.env.CRON_SECRET. */
|
|
77
|
+
cronSecret?: string | null;
|
|
78
|
+
/** How long finished runs are kept. Default "30d". */
|
|
79
|
+
retention?: Duration;
|
|
80
|
+
/** Applied to every job unless the job sets its own. */
|
|
81
|
+
defaults?: Pick<JobOptions, "grace" | "timeout" | "timezone" | "failuresBeforeAlert">;
|
|
82
|
+
/** Called with anything that goes wrong outside a job: an alert channel failing, a triage timeout. */
|
|
83
|
+
onError?: (error: unknown, where: string) => void;
|
|
84
|
+
/** The clock. Tests use this. */
|
|
85
|
+
now?: () => number;
|
|
86
|
+
}
|
|
87
|
+
interface ExecuteResult<T> {
|
|
88
|
+
run: Run;
|
|
89
|
+
result: T | undefined;
|
|
90
|
+
error: unknown;
|
|
91
|
+
threw: boolean;
|
|
92
|
+
}
|
|
93
|
+
declare class CronWatch {
|
|
94
|
+
readonly store: Store;
|
|
95
|
+
readonly alerts: AlertChannel[];
|
|
96
|
+
readonly triage: TriageFn | undefined;
|
|
97
|
+
readonly cronSecret: string | null;
|
|
98
|
+
readonly retentionMs: number;
|
|
99
|
+
readonly now: () => number;
|
|
100
|
+
readonly onError: (error: unknown, where: string) => void;
|
|
101
|
+
private readonly defaults;
|
|
102
|
+
private readonly definitions;
|
|
103
|
+
private readonly synced;
|
|
104
|
+
private ready;
|
|
105
|
+
private checking;
|
|
106
|
+
private lastPruneAt;
|
|
107
|
+
private timer;
|
|
108
|
+
private usingDefaultStore;
|
|
109
|
+
constructor(options?: CronWatchOptions);
|
|
110
|
+
/** Declare a job. Call it once, at module level, and keep the handle. */
|
|
111
|
+
job(name: string, options?: JobOptions): JobHandle;
|
|
112
|
+
/** Run a job by name without keeping a handle. Defines it on first use. */
|
|
113
|
+
run<T>(name: string, fn: JobFn<T>): Promise<T>;
|
|
114
|
+
run<T>(name: string, options: JobOptions, fn: JobFn<T>): Promise<T>;
|
|
115
|
+
/** The definitions declared in this process. */
|
|
116
|
+
definedJobs(): JobDefinition[];
|
|
117
|
+
private handle;
|
|
118
|
+
private ensureReady;
|
|
119
|
+
private sync;
|
|
120
|
+
/** Runs a function as a recorded run. Never throws for the job's own error; see `threw`. */
|
|
121
|
+
execute<T>(definition: JobDefinition, fn: JobFn<T>, trigger: string): Promise<ExecuteResult<T>>;
|
|
122
|
+
/**
|
|
123
|
+
* Look for missed and stuck runs across every job, send alerts, and prune
|
|
124
|
+
* old runs. Call it from an interval (start()), a cron hitting the mounted
|
|
125
|
+
* routes, or by hand. Concurrent calls share one check.
|
|
126
|
+
*/
|
|
127
|
+
check(): Promise<CheckResult>;
|
|
128
|
+
private runCheck;
|
|
129
|
+
/** Every job the store knows about, with its health. Does not send alerts. */
|
|
130
|
+
jobs(): Promise<JobSummary[]>;
|
|
131
|
+
jobSummary(name: string): Promise<JobSummary | null>;
|
|
132
|
+
runs(name: string, limit?: number): Promise<Run[]>;
|
|
133
|
+
getRun(id: string): Promise<Run | null>;
|
|
134
|
+
/** Stop alerts for a job for a while. State keeps updating underneath. */
|
|
135
|
+
silence(name: string, duration: Duration): Promise<JobState>;
|
|
136
|
+
unsilence(name: string): Promise<JobState>;
|
|
137
|
+
/** Remove a job and its runs from the store. A job still declared in code comes back on its next run. */
|
|
138
|
+
forget(name: string): Promise<void>;
|
|
139
|
+
/** The dashboard and JSON API as fetch-style handlers. See createRoutes(). */
|
|
140
|
+
routes(options?: RoutesOptions): Routes;
|
|
141
|
+
/** Check on an interval, for long-running servers. Default every minute. */
|
|
142
|
+
start(every?: Duration): void;
|
|
143
|
+
stop(): void;
|
|
144
|
+
close(): Promise<void>;
|
|
145
|
+
private summarize;
|
|
146
|
+
/** Save an evaluation's state, honouring silence, and send its alerts. */
|
|
147
|
+
private settle;
|
|
148
|
+
private dispatch;
|
|
149
|
+
}
|
|
150
|
+
/** Writes alerts to the console. The default channel. */
|
|
151
|
+
declare function consoleChannel(): AlertChannel;
|
|
152
|
+
/** Wrap any function as an alert channel. */
|
|
153
|
+
declare function custom(name: string, send: (alert: Alert) => Promise<void> | void): AlertChannel;
|
|
154
|
+
|
|
155
|
+
declare function json(body: unknown, status?: number, headers?: Record<string, string>): Response;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Keeps everything in process memory. The default when no store is given,
|
|
159
|
+
* good for tests and for trying the library out. State is gone on restart,
|
|
160
|
+
* so a missed run cannot be noticed across one.
|
|
161
|
+
*/
|
|
162
|
+
declare function memory(): Store;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* "15m" -> 900000. Accepts a plain number of milliseconds, and compound
|
|
166
|
+
* strings such as "1h30m". Whitespace between parts is fine.
|
|
167
|
+
*/
|
|
168
|
+
declare function parseDuration(value: Duration, label?: string): number;
|
|
169
|
+
/** 90000 -> "1m 30s". For messages, not for parsing back. */
|
|
170
|
+
declare function formatDuration(ms: number): string;
|
|
171
|
+
/** "5 minutes ago", "in 2h". Relative to `now`. */
|
|
172
|
+
declare function formatRelative(at: number, now: number): string;
|
|
173
|
+
|
|
174
|
+
interface ParsedSchedule {
|
|
175
|
+
kind: "cron" | "interval";
|
|
176
|
+
source: string;
|
|
177
|
+
/** For intervals, the period in milliseconds. */
|
|
178
|
+
everyMs?: number;
|
|
179
|
+
cron?: Cron;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* "0 2 * * *" (cron, five or six fields), "@hourly", or "every 5m".
|
|
183
|
+
* Parsed once per (schedule, timezone) pair and cached. The croner instance
|
|
184
|
+
* gets no callback, so it schedules nothing; it is only used to compute fire
|
|
185
|
+
* times. Without a timezone the expression is read in the process timezone,
|
|
186
|
+
* like crontab. Vercel and GitHub Actions run their crons in UTC, so pass
|
|
187
|
+
* timezone: "UTC" for those.
|
|
188
|
+
*/
|
|
189
|
+
declare function parseSchedule(schedule: string, timezone?: string): ParsedSchedule;
|
|
190
|
+
/** The next time the cron fires strictly after `from`. */
|
|
191
|
+
declare function nextFire(parsed: ParsedSchedule, from: number, lastRunAt: number | null): number | null;
|
|
192
|
+
/**
|
|
193
|
+
* The most recent time the cron fired at or before `now`, or null when the
|
|
194
|
+
* expression never fires in the year before `now`.
|
|
195
|
+
*
|
|
196
|
+
* croner only looks forward, so this searches: widen a window behind `now`
|
|
197
|
+
* until a fire time falls inside it, then bisect on the window's start for
|
|
198
|
+
* the latest start whose next fire is still at or before `now`.
|
|
199
|
+
*/
|
|
200
|
+
declare function previousFire(parsed: ParsedSchedule, now: number): number | null;
|
|
201
|
+
|
|
202
|
+
interface AlertDraft {
|
|
203
|
+
type: Condition | "recovered";
|
|
204
|
+
run: Run | null;
|
|
205
|
+
details: Record<string, unknown>;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** Turns a draft into the title and message every channel shows. */
|
|
209
|
+
declare function composeAlert(draft: AlertDraft, def: StoredJobDefinition, now: number): Alert;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Create a CronWatch client. One per app, at module level:
|
|
213
|
+
*
|
|
214
|
+
* export const cw = cronwatch({ store: sqlite({ path: "./data/cronwatch.db" }), alerts: [slack({ webhookUrl })] });
|
|
215
|
+
* export const nightly = cw.job("nightly-report", { schedule: "0 2 * * *", grace: "15m" });
|
|
216
|
+
*/
|
|
217
|
+
declare function cronwatch(options?: CronWatchOptions): CronWatch;
|
|
218
|
+
|
|
219
|
+
export { Alert, AlertChannel, CheckResult, Condition, CronWatch, type CronWatchOptions, Duration, type HandlerFn, type HandlerOptions, type JobContext, JobDefinition, type JobFn, type JobHandle, JobOptions, JobState, JobSummary, type Routes, type RoutesOptions, Run, Store, StoredJobDefinition, TriageFn, composeAlert, consoleChannel, createRoutes, cronwatch, custom, formatDuration, formatRelative, json, memory, nextFire, parseDuration, parseSchedule, previousFire };
|