@cronwatch/sdk 0.8.0 → 0.9.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/dist/anthropic.d.cts +1 -1
- package/dist/anthropic.d.ts +1 -1
- package/dist/bugsnag.d.cts +1 -1
- package/dist/bugsnag.d.ts +1 -1
- package/dist/{client-B5hM4l-D.d.ts → client-CQm-8-mR.d.ts} +13 -2
- package/dist/{client-Di5HAWQz.d.cts → client-D35cfnNV.d.cts} +13 -2
- package/dist/d1.cjs +29 -19
- package/dist/d1.cjs.map +1 -1
- package/dist/d1.d.cts +1 -1
- package/dist/d1.d.ts +1 -1
- package/dist/d1.js +29 -19
- package/dist/d1.js.map +1 -1
- package/dist/datadog.d.cts +1 -1
- package/dist/datadog.d.ts +1 -1
- package/dist/discord.d.cts +1 -1
- package/dist/discord.d.ts +1 -1
- package/dist/{email-Ciq7GRn4.d.ts → email-BxCp9RQV.d.ts} +1 -1
- package/dist/{email-DX6gkd5H.d.cts → email-D1d5niMy.d.cts} +1 -1
- package/dist/honeybadger.d.cts +1 -1
- package/dist/honeybadger.d.ts +1 -1
- package/dist/index.cjs +50 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +50 -15
- package/dist/index.js.map +1 -1
- package/dist/mailgun.d.cts +2 -2
- package/dist/mailgun.d.ts +2 -2
- package/dist/newrelic.d.cts +1 -1
- package/dist/newrelic.d.ts +1 -1
- package/dist/pg-cron.cjs +45 -4
- package/dist/pg-cron.cjs.map +1 -1
- package/dist/pg-cron.d.cts +5 -2
- package/dist/pg-cron.d.ts +5 -2
- package/dist/pg-cron.js +45 -4
- package/dist/pg-cron.js.map +1 -1
- package/dist/postgres.cjs +22 -14
- package/dist/postgres.cjs.map +1 -1
- package/dist/postgres.d.cts +1 -1
- package/dist/postgres.d.ts +1 -1
- package/dist/postgres.js +22 -14
- package/dist/postgres.js.map +1 -1
- package/dist/postmark.d.cts +2 -2
- package/dist/postmark.d.ts +2 -2
- package/dist/resend.d.cts +2 -2
- package/dist/resend.d.ts +2 -2
- package/dist/rollbar.d.cts +1 -1
- package/dist/rollbar.d.ts +1 -1
- package/dist/sendgrid.d.cts +2 -2
- package/dist/sendgrid.d.ts +2 -2
- package/dist/sentry.d.cts +1 -1
- package/dist/sentry.d.ts +1 -1
- package/dist/ses.d.cts +2 -2
- package/dist/ses.d.ts +2 -2
- package/dist/slack.d.cts +1 -1
- package/dist/slack.d.ts +1 -1
- package/dist/sqlite.cjs +26 -18
- package/dist/sqlite.cjs.map +1 -1
- package/dist/sqlite.d.cts +1 -1
- package/dist/sqlite.d.ts +1 -1
- package/dist/sqlite.js +26 -18
- package/dist/sqlite.js.map +1 -1
- package/dist/twilio.d.cts +1 -1
- package/dist/twilio.d.ts +1 -1
- package/dist/{types-BjBbCGeJ.d.cts → types-Cz47Boks.d.cts} +6 -0
- package/dist/{types-BjBbCGeJ.d.ts → types-Cz47Boks.d.ts} +6 -0
- package/dist/webhook.d.cts +1 -1
- package/dist/webhook.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -272,6 +272,11 @@ function stateVersion(state) {
|
|
|
272
272
|
const version = state?.version;
|
|
273
273
|
return typeof version === "number" && Number.isSafeInteger(version) && version >= 0 ? version + 0 : 0;
|
|
274
274
|
}
|
|
275
|
+
function failureCount(state) {
|
|
276
|
+
const count = state?.consecutiveFailures;
|
|
277
|
+
if (typeof count !== "number" || !Number.isInteger(count) || count <= 0) return 0;
|
|
278
|
+
return Math.min(count, MAX_DURATION_MS);
|
|
279
|
+
}
|
|
275
280
|
function emptyState(job) {
|
|
276
281
|
return { job, open: {}, consecutiveFailures: 0, silencedUntil: null, lastAlertAt: null, pendingRecovery: [], undelivered: [] };
|
|
277
282
|
}
|
|
@@ -281,6 +286,7 @@ function normalizeState(state, job) {
|
|
|
281
286
|
...emptyState(job),
|
|
282
287
|
...state,
|
|
283
288
|
open: { ...state.open },
|
|
289
|
+
consecutiveFailures: failureCount(state),
|
|
284
290
|
pendingRecovery: [...state.pendingRecovery ?? []],
|
|
285
291
|
undelivered: [...state.undelivered ?? []]
|
|
286
292
|
};
|
|
@@ -379,7 +385,7 @@ function onRunFinish(def, run, state, history, now) {
|
|
|
379
385
|
}
|
|
380
386
|
return { state: next, alerts };
|
|
381
387
|
}
|
|
382
|
-
next.consecutiveFailures
|
|
388
|
+
next.consecutiveFailures = Math.min(next.consecutiveFailures + 1, MAX_DURATION_MS);
|
|
383
389
|
closeCondition(next, "missed");
|
|
384
390
|
const threshold = Math.max(1, def.failuresBeforeAlert ?? 1);
|
|
385
391
|
const condition = run.status === "timeout" ? "stuck" : "failed";
|
|
@@ -593,6 +599,9 @@ function capOutput(text) {
|
|
|
593
599
|
function stripNul(text) {
|
|
594
600
|
return text.includes("\0") ? text.replace(/\u0000/g, "") : text;
|
|
595
601
|
}
|
|
602
|
+
function stripJsonNul(json2) {
|
|
603
|
+
return json2.includes("\\u0000") ? json2.replace(/\\(u0000|[\s\S])/g, (escape, next) => next === "u0000" ? "" : escape) : json2;
|
|
604
|
+
}
|
|
596
605
|
function errorMessage(error) {
|
|
597
606
|
return capOutput(describeError(error));
|
|
598
607
|
}
|
|
@@ -1845,13 +1854,21 @@ function memory() {
|
|
|
1845
1854
|
const states = /* @__PURE__ */ new Map();
|
|
1846
1855
|
let seq = 0;
|
|
1847
1856
|
const clone = (v) => JSON.parse(JSON.stringify(v));
|
|
1857
|
+
const kept = (v) => JSON.parse(stripJsonNul(JSON.stringify(v)));
|
|
1858
|
+
const keptRun = (run) => ({
|
|
1859
|
+
...clone(run),
|
|
1860
|
+
trigger: stripNul(run.trigger),
|
|
1861
|
+
output: run.output === null ? null : stripNul(run.output),
|
|
1862
|
+
error: run.error === null ? null : stripNul(run.error),
|
|
1863
|
+
metrics: kept(run.metrics)
|
|
1864
|
+
});
|
|
1848
1865
|
const byName = (a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
|
|
1849
1866
|
return {
|
|
1850
1867
|
async upsertJob(definition, now) {
|
|
1851
1868
|
const existing = jobs.get(definition.name);
|
|
1852
1869
|
jobs.set(definition.name, {
|
|
1853
1870
|
name: definition.name,
|
|
1854
|
-
definition:
|
|
1871
|
+
definition: kept(definition),
|
|
1855
1872
|
createdAt: existing?.createdAt ?? now,
|
|
1856
1873
|
updatedAt: now
|
|
1857
1874
|
});
|
|
@@ -1873,19 +1890,19 @@ function memory() {
|
|
|
1873
1890
|
},
|
|
1874
1891
|
async insertRun(run) {
|
|
1875
1892
|
if (runs.has(run.id)) throw new Error(`run ${run.id} already exists`);
|
|
1876
|
-
runs.set(run.id,
|
|
1893
|
+
runs.set(run.id, keptRun(run));
|
|
1877
1894
|
order.set(run.id, ++seq);
|
|
1878
1895
|
},
|
|
1879
1896
|
async updateRun(run) {
|
|
1880
1897
|
const existing = runs.get(run.id);
|
|
1881
1898
|
if (!existing) return;
|
|
1882
|
-
const { status, finishedAt, durationMs, error, output, metrics } =
|
|
1899
|
+
const { status, finishedAt, durationMs, error, output, metrics } = keptRun(run);
|
|
1883
1900
|
runs.set(run.id, { ...existing, status, finishedAt, durationMs, error, output, metrics });
|
|
1884
1901
|
},
|
|
1885
1902
|
async updateRunIf(run, fromStatuses) {
|
|
1886
1903
|
const existing = runs.get(run.id);
|
|
1887
1904
|
if (!existing || !fromStatuses.includes(existing.status)) return false;
|
|
1888
|
-
const { status, finishedAt, durationMs, error, output, metrics } =
|
|
1905
|
+
const { status, finishedAt, durationMs, error, output, metrics } = keptRun(run);
|
|
1889
1906
|
runs.set(run.id, { ...existing, status, finishedAt, durationMs, error, output, metrics });
|
|
1890
1907
|
return true;
|
|
1891
1908
|
},
|
|
@@ -1908,11 +1925,11 @@ function memory() {
|
|
|
1908
1925
|
return s ? clone(s) : null;
|
|
1909
1926
|
},
|
|
1910
1927
|
async setState(state) {
|
|
1911
|
-
states.set(state.job,
|
|
1928
|
+
states.set(state.job, kept(state));
|
|
1912
1929
|
},
|
|
1913
1930
|
async compareAndSetState(state, expectedVersion) {
|
|
1914
1931
|
if (stateVersion(states.get(state.job)) !== expectedVersion) return false;
|
|
1915
|
-
states.set(state.job,
|
|
1932
|
+
states.set(state.job, kept(state));
|
|
1916
1933
|
return true;
|
|
1917
1934
|
},
|
|
1918
1935
|
async prune(before) {
|
|
@@ -2000,6 +2017,8 @@ var CronWatch = class {
|
|
|
2000
2017
|
synced = /* @__PURE__ */ new Set();
|
|
2001
2018
|
/** The tail of each job's queue of state updates. See serial(). */
|
|
2002
2019
|
queues = /* @__PURE__ */ new Map();
|
|
2020
|
+
/** The tail of each job's queue of declaration writes. See sync(). */
|
|
2021
|
+
syncing = /* @__PURE__ */ new Map();
|
|
2003
2022
|
/** start() calls with an id still in flight, so two at once in this process record one run. */
|
|
2004
2023
|
starting = /* @__PURE__ */ new Map();
|
|
2005
2024
|
ready = null;
|
|
@@ -2138,26 +2157,40 @@ var CronWatch = class {
|
|
|
2138
2157
|
}
|
|
2139
2158
|
await this.ready;
|
|
2140
2159
|
}
|
|
2160
|
+
/**
|
|
2161
|
+
* Writes the declaration of `definition`'s name as it stands, unless the
|
|
2162
|
+
* store has it. A handle kept from an earlier declaration writes the one
|
|
2163
|
+
* that replaced it, never its own over it, and one forgotten since writes
|
|
2164
|
+
* its own. The writes of one name take turns, in the order they were asked
|
|
2165
|
+
* for, so one still under way cannot land after a later one; and a name
|
|
2166
|
+
* declared again while its write was under way is still to be written.
|
|
2167
|
+
*/
|
|
2141
2168
|
async sync(definition) {
|
|
2142
2169
|
await this.ensureReady();
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
this.
|
|
2170
|
+
const name = definition.name;
|
|
2171
|
+
if (this.synced.has(name)) return;
|
|
2172
|
+
await this.serial(name, async () => {
|
|
2173
|
+
if (this.synced.has(name)) return;
|
|
2174
|
+
const standing = this.definitions.get(name) ?? definition;
|
|
2175
|
+
await this.store.upsertJob(toStored(standing), this.now());
|
|
2176
|
+
if ((this.definitions.get(name) ?? standing) === standing) this.synced.add(name);
|
|
2177
|
+
}, this.syncing);
|
|
2146
2178
|
}
|
|
2147
2179
|
/**
|
|
2148
2180
|
* Runs `fn` after every earlier state update for the same job has settled,
|
|
2149
2181
|
* so two runs (or a run and a check) in this process never read and write
|
|
2150
2182
|
* the job's state over each other. Other processes are coordinated by
|
|
2151
|
-
* updateState() instead.
|
|
2183
|
+
* updateState() instead. sync() queues a job's declaration writes the same
|
|
2184
|
+
* way, in `syncing`.
|
|
2152
2185
|
*/
|
|
2153
|
-
serial(job, fn) {
|
|
2154
|
-
const result = (
|
|
2186
|
+
serial(job, fn, queues = this.queues) {
|
|
2187
|
+
const result = (queues.get(job) ?? Promise.resolve()).then(fn);
|
|
2155
2188
|
const tail2 = result.then(() => {
|
|
2156
2189
|
}, () => {
|
|
2157
2190
|
});
|
|
2158
|
-
|
|
2191
|
+
queues.set(job, tail2);
|
|
2159
2192
|
void tail2.then(() => {
|
|
2160
|
-
if (
|
|
2193
|
+
if (queues.get(job) === tail2) queues.delete(job);
|
|
2161
2194
|
});
|
|
2162
2195
|
return result;
|
|
2163
2196
|
}
|
|
@@ -2557,6 +2590,7 @@ ${id}`;
|
|
|
2557
2590
|
async recordRun(input, options = {}) {
|
|
2558
2591
|
const declared = this.definitions.get(input.job);
|
|
2559
2592
|
if (!declared) throw new Error(`recordRun: job "${input.job}" is not declared; call job() first`);
|
|
2593
|
+
if (input.id.includes("\0")) throw new Error(`recordRun: run ids cannot contain a NUL character (job "${input.job}")`);
|
|
2560
2594
|
await this.sync(declared);
|
|
2561
2595
|
const run = { ...input, metrics: { ...input.metrics } };
|
|
2562
2596
|
if (run.status === "ok") {
|
|
@@ -2927,6 +2961,7 @@ function checkRunId(job, id, method) {
|
|
|
2927
2961
|
if (typeof id !== "string" || id.length === 0 || id.length > 200) {
|
|
2928
2962
|
throw new Error(`job "${job}": ${method}() needs a run id of 1 to 200 characters (got ${typeof id === "string" ? `${id.length} characters` : typeof id})`);
|
|
2929
2963
|
}
|
|
2964
|
+
if (id.includes("\0")) throw new Error(`job "${job}": ${method}() cannot take a run id containing a NUL character`);
|
|
2930
2965
|
if (id.startsWith(RESERVED_RUN_ID_PREFIX)) {
|
|
2931
2966
|
throw new Error(`job "${job}": ${method}() cannot take a run id starting with "${RESERVED_RUN_ID_PREFIX}", which the pg_cron source uses for its runs`);
|
|
2932
2967
|
}
|