@cronwatch/sdk 0.14.0 → 0.14.1
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/bugsnag.cjs +19 -4
- package/dist/bugsnag.cjs.map +1 -1
- package/dist/bugsnag.js +19 -4
- package/dist/bugsnag.js.map +1 -1
- package/dist/datadog.cjs +19 -4
- package/dist/datadog.cjs.map +1 -1
- package/dist/datadog.js +19 -4
- package/dist/datadog.js.map +1 -1
- package/dist/discord.cjs +27 -9
- package/dist/discord.cjs.map +1 -1
- package/dist/discord.js +27 -9
- package/dist/discord.js.map +1 -1
- package/dist/honeybadger.cjs +19 -4
- package/dist/honeybadger.cjs.map +1 -1
- package/dist/honeybadger.js +19 -4
- package/dist/honeybadger.js.map +1 -1
- package/dist/index.cjs +33 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +33 -17
- package/dist/index.js.map +1 -1
- package/dist/mailgun.cjs +19 -4
- package/dist/mailgun.cjs.map +1 -1
- package/dist/mailgun.js +19 -4
- package/dist/mailgun.js.map +1 -1
- package/dist/newrelic.cjs +19 -4
- package/dist/newrelic.cjs.map +1 -1
- package/dist/newrelic.js +19 -4
- package/dist/newrelic.js.map +1 -1
- package/dist/postmark.cjs +19 -4
- package/dist/postmark.cjs.map +1 -1
- package/dist/postmark.js +19 -4
- package/dist/postmark.js.map +1 -1
- package/dist/resend.cjs +19 -4
- package/dist/resend.cjs.map +1 -1
- package/dist/resend.js +19 -4
- package/dist/resend.js.map +1 -1
- package/dist/rollbar.cjs +19 -4
- package/dist/rollbar.cjs.map +1 -1
- package/dist/rollbar.js +19 -4
- package/dist/rollbar.js.map +1 -1
- package/dist/sendgrid.cjs +19 -4
- package/dist/sendgrid.cjs.map +1 -1
- package/dist/sendgrid.js +19 -4
- package/dist/sendgrid.js.map +1 -1
- package/dist/sentry.cjs +19 -4
- package/dist/sentry.cjs.map +1 -1
- package/dist/sentry.js +19 -4
- package/dist/sentry.js.map +1 -1
- package/dist/ses.cjs +19 -4
- package/dist/ses.cjs.map +1 -1
- package/dist/ses.js +19 -4
- package/dist/ses.js.map +1 -1
- package/dist/slack.cjs +27 -9
- package/dist/slack.cjs.map +1 -1
- package/dist/slack.js +27 -9
- package/dist/slack.js.map +1 -1
- package/dist/twilio.cjs +19 -4
- package/dist/twilio.cjs.map +1 -1
- package/dist/twilio.js +19 -4
- package/dist/twilio.js.map +1 -1
- package/dist/webhook.cjs +29 -7
- package/dist/webhook.cjs.map +1 -1
- package/dist/webhook.js +29 -7
- package/dist/webhook.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -993,11 +993,15 @@ function stringify(part) {
|
|
|
993
993
|
}
|
|
994
994
|
}
|
|
995
995
|
function createRecorder(run) {
|
|
996
|
+
const window = OUTPUT_CAP + REDACT_EDGE + 2;
|
|
997
|
+
const copy = (text) => JSON.parse(JSON.stringify(text));
|
|
996
998
|
const lines = [];
|
|
997
999
|
let size = 0;
|
|
998
1000
|
const head = [];
|
|
999
1001
|
let headSize = 0;
|
|
1000
|
-
let
|
|
1002
|
+
let whole = "";
|
|
1003
|
+
let tail2 = "";
|
|
1004
|
+
let logged = false;
|
|
1001
1005
|
const metrics = {};
|
|
1002
1006
|
const controller = new AbortController();
|
|
1003
1007
|
const context = {
|
|
@@ -1006,16 +1010,23 @@ function createRecorder(run) {
|
|
|
1006
1010
|
startedAt: run.startedAt,
|
|
1007
1011
|
signal: controller.signal,
|
|
1008
1012
|
log(...parts) {
|
|
1009
|
-
|
|
1013
|
+
let line = parts.map(stringify).join(" ");
|
|
1014
|
+
const separator = logged ? "\n" : "";
|
|
1015
|
+
logged = true;
|
|
1016
|
+
if (whole !== null) whole = whole.length + separator.length + line.length <= 2 * OUTPUT_CAP ? whole + separator + line : null;
|
|
1017
|
+
tail2 = copy((tail2 + separator + copy(line.slice(-OUTPUT_CAP))).slice(-OUTPUT_CAP));
|
|
1010
1018
|
if (headSize < OUTPUT_CAP) {
|
|
1011
|
-
head.push(line);
|
|
1019
|
+
head.push(copy(line.slice(0, OUTPUT_CAP - headSize)));
|
|
1012
1020
|
headSize += line.length + 1;
|
|
1013
1021
|
}
|
|
1022
|
+
line = stripNul(line);
|
|
1023
|
+
if (line.length >= window) {
|
|
1024
|
+
line = copy(line.slice(-68609));
|
|
1025
|
+
}
|
|
1014
1026
|
lines.push(line);
|
|
1015
1027
|
size += line.length + 1;
|
|
1016
|
-
while (size >
|
|
1028
|
+
while (size > window && lines.length > 1) {
|
|
1017
1029
|
size -= lines.shift().length + 1;
|
|
1018
|
-
dropped = true;
|
|
1019
1030
|
}
|
|
1020
1031
|
},
|
|
1021
1032
|
metric(name, value) {
|
|
@@ -1032,10 +1043,8 @@ function createRecorder(run) {
|
|
|
1032
1043
|
context,
|
|
1033
1044
|
output: () => lines.length === 0 ? null : lines.join("\n"),
|
|
1034
1045
|
expectText: () => {
|
|
1035
|
-
if (
|
|
1036
|
-
|
|
1037
|
-
if (!dropped && all.length <= 2 * OUTPUT_CAP) return all;
|
|
1038
|
-
return head.join("\n").slice(0, OUTPUT_CAP) + "\n" + all.slice(-OUTPUT_CAP);
|
|
1046
|
+
if (!logged) return null;
|
|
1047
|
+
return whole ?? head.join("\n").slice(0, OUTPUT_CAP) + "\n" + tail2;
|
|
1039
1048
|
},
|
|
1040
1049
|
metrics: () => ({ ...metrics }),
|
|
1041
1050
|
abort: () => controller.abort()
|
|
@@ -1209,7 +1218,7 @@ function staticAsset(path, base) {
|
|
|
1209
1218
|
}
|
|
1210
1219
|
|
|
1211
1220
|
// src/version.ts
|
|
1212
|
-
var VERSION = "0.14.
|
|
1221
|
+
var VERSION = "0.14.1";
|
|
1213
1222
|
var API_VERSION = 1;
|
|
1214
1223
|
|
|
1215
1224
|
// src/routes/timeline.ts
|
|
@@ -1999,6 +2008,7 @@ function stripBase(pathname, base) {
|
|
|
1999
2008
|
}
|
|
2000
2009
|
var MAX_REQUEST_BODY = 1 << 20;
|
|
2001
2010
|
var TOO_LARGE = /* @__PURE__ */ Symbol("too large");
|
|
2011
|
+
var BAD_BODY = /* @__PURE__ */ Symbol("malformed body");
|
|
2002
2012
|
async function readLimited(request) {
|
|
2003
2013
|
const length = Number(request.headers.get("content-length"));
|
|
2004
2014
|
if (Number.isFinite(length) && length > MAX_REQUEST_BODY) return TOO_LARGE;
|
|
@@ -2045,14 +2055,14 @@ async function readBody(request) {
|
|
|
2045
2055
|
try {
|
|
2046
2056
|
if (json2) {
|
|
2047
2057
|
const data = await copy.json();
|
|
2048
|
-
return typeof data === "object" && data !== null ? Object.fromEntries(Object.entries(data).map(([k, v]) => [k, String(v)])) :
|
|
2058
|
+
return typeof data === "object" && data !== null && !Array.isArray(data) ? Object.fromEntries(Object.entries(data).map(([k, v]) => [k, String(v)])) : BAD_BODY;
|
|
2049
2059
|
}
|
|
2050
2060
|
const fields = await copy.formData();
|
|
2051
2061
|
const out = {};
|
|
2052
2062
|
for (const [k, v] of fields.entries()) out[k] = String(v);
|
|
2053
2063
|
return out;
|
|
2054
2064
|
} catch {
|
|
2055
|
-
return
|
|
2065
|
+
return BAD_BODY;
|
|
2056
2066
|
}
|
|
2057
2067
|
}
|
|
2058
2068
|
function crossSite(request, publicOrigin) {
|
|
@@ -2118,6 +2128,7 @@ function buildRoutes(cw, options = {}) {
|
|
|
2118
2128
|
const signInPage = () => generated ? html(messagePage("Sign in", "CRONWATCH_TOKEN is not set, so this development server made a token. The sign-in link is in the server log: open it once, or enter the token from it below, and this browser stays signed in.", base, true), 401) : html(messagePage("Sign in", "Enter your CRONWATCH_TOKEN and this browser stays signed in.", base, true), 401);
|
|
2119
2129
|
if (token && method === "POST" && path === "/signin") {
|
|
2120
2130
|
const body = await readBody(request);
|
|
2131
|
+
if (body === BAD_BODY) return html(messagePage("Bad request", "Malformed request body", base), 400);
|
|
2121
2132
|
const sent = body === TOO_LARGE ? void 0 : body.token;
|
|
2122
2133
|
if (sent === void 0 || !constantTimeEqual(sent, token)) return signInPage();
|
|
2123
2134
|
return redirect(signInReturn(request.headers.get("referer"), publicOrigin, base), { "set-cookie": await signInCookie() });
|
|
@@ -2175,6 +2186,7 @@ function buildRoutes(cw, options = {}) {
|
|
|
2175
2186
|
if (parts[2] === "silence") {
|
|
2176
2187
|
const body = await readBody(request);
|
|
2177
2188
|
if (body === TOO_LARGE) return html(messagePage("Not silenced", "The request was too large.", base), 413);
|
|
2189
|
+
if (body === BAD_BODY) return html(messagePage("Not silenced", "Malformed request body", base), 400);
|
|
2178
2190
|
let duration;
|
|
2179
2191
|
try {
|
|
2180
2192
|
duration = silenceDuration(body.for);
|
|
@@ -2212,6 +2224,7 @@ function buildRoutes(cw, options = {}) {
|
|
|
2212
2224
|
if (rest[2] === "silence") {
|
|
2213
2225
|
const body = await readBody(request);
|
|
2214
2226
|
if (body === TOO_LARGE) return api({ ok: false, error: "Request body too large" }, 413);
|
|
2227
|
+
if (body === BAD_BODY) return api({ ok: false, error: "Malformed request body" }, 400);
|
|
2215
2228
|
let duration;
|
|
2216
2229
|
try {
|
|
2217
2230
|
duration = silenceDuration(body.for ?? url.searchParams.get("for"));
|
|
@@ -2847,9 +2860,10 @@ var Cronwatch = class {
|
|
|
2847
2860
|
if (stored.job !== run.job) return `belongs to job "${stored.job}"`;
|
|
2848
2861
|
}
|
|
2849
2862
|
}
|
|
2863
|
+
const tracked = (await this.readState(run.job)).pendingRuns?.includes(run.id) ?? false;
|
|
2850
2864
|
const claim = await this.claimFinish(run);
|
|
2851
2865
|
if ("ignored" in claim) return claim.ignored;
|
|
2852
|
-
if (!claim.lateAfterTimeout || run.status === "ok") await this.finishRun(toStored(definition), run, finishedAt);
|
|
2866
|
+
if (!claim.lateAfterTimeout || run.status === "ok") await this.finishRun(toStored(definition), run, finishedAt, tracked && !claim.lateAfterTimeout);
|
|
2853
2867
|
return null;
|
|
2854
2868
|
}
|
|
2855
2869
|
/** A conditional write (Store.updateRunIf), or for a store without one, a read then a plain write. */
|
|
@@ -3144,7 +3158,7 @@ ${id}`;
|
|
|
3144
3158
|
if (!evaluate) return [];
|
|
3145
3159
|
await this.updateState(run.job, (before) => ({ state: holdRun(onRunStart(definition, run, before, this.now()), run.id), result: void 0 }));
|
|
3146
3160
|
if (run.status === "running") return [];
|
|
3147
|
-
return this.finishRun(definition, run, this.now());
|
|
3161
|
+
return this.finishRun(definition, run, this.now(), true);
|
|
3148
3162
|
}
|
|
3149
3163
|
/** recordRun() for a run already stored. */
|
|
3150
3164
|
async recordOver(definition, stored, run, evaluate) {
|
|
@@ -3153,6 +3167,7 @@ ${id}`;
|
|
|
3153
3167
|
return [];
|
|
3154
3168
|
}
|
|
3155
3169
|
if (stored.status !== "running" && stored.status !== "timeout" || run.status === "running") return [];
|
|
3170
|
+
const tracked = (await this.readState(run.job)).pendingRuns?.includes(run.id) ?? false;
|
|
3156
3171
|
const claim = await this.claimFinish(run);
|
|
3157
3172
|
if ("ignored" in claim) {
|
|
3158
3173
|
this.report(new Error(`run ${run.id} of ${run.job} ${claim.ignored}; ignored`), `recording ${run.job}`);
|
|
@@ -3163,18 +3178,19 @@ ${id}`;
|
|
|
3163
3178
|
return [];
|
|
3164
3179
|
}
|
|
3165
3180
|
if (claim.lateAfterTimeout && run.status !== "ok") return [];
|
|
3166
|
-
return this.finishRun(definition, run, this.now());
|
|
3181
|
+
return this.finishRun(definition, run, this.now(), tracked && !claim.lateAfterTimeout);
|
|
3167
3182
|
}
|
|
3168
3183
|
/**
|
|
3169
3184
|
* Evaluate a finished run (ok, failed, or timed out by a check), already
|
|
3170
3185
|
* written, against the job's state and send what that produces. The
|
|
3171
3186
|
* alerts are written with that state (see outbox()). Never throws.
|
|
3172
3187
|
*/
|
|
3173
|
-
async finishRun(definition, run, now) {
|
|
3188
|
+
async finishRun(definition, run, now, pendingOnly = false) {
|
|
3174
3189
|
let held;
|
|
3175
3190
|
try {
|
|
3176
3191
|
let history = null;
|
|
3177
3192
|
({ result: held } = await this.updateState(run.job, async (previous) => {
|
|
3193
|
+
if (pendingOnly && !(previous.pendingRuns ?? []).includes(run.id)) return { state: previous, result: { alerts: [], dropped: 0 } };
|
|
3178
3194
|
history ??= await this.history(run);
|
|
3179
3195
|
const before = releaseRun(previous, run.id);
|
|
3180
3196
|
return this.outbox(applySilence(before, onRunFinish(definition, run, before, history, now), now), definition, now);
|
|
@@ -3319,7 +3335,7 @@ ${id}`;
|
|
|
3319
3335
|
continue;
|
|
3320
3336
|
}
|
|
3321
3337
|
if (run.status === "running" || typeof run.finishedAt !== "number" || run.finishedAt > now - SEND_LEASE_MS) continue;
|
|
3322
|
-
alerts.push(...await this.finishRun(stored.definition, run, now));
|
|
3338
|
+
alerts.push(...await this.finishRun(stored.definition, run, now, true));
|
|
3323
3339
|
} catch (e) {
|
|
3324
3340
|
this.onError(e, `evaluating run ${id} of ${stored.name}`);
|
|
3325
3341
|
}
|