Skip to content

Commit 934927f

Browse files
committed
refactor: dedupe cron lowercase helpers
1 parent bbe5a4b commit 934927f

6 files changed

Lines changed: 31 additions & 24 deletions

File tree

src/cron/delivery-field-schemas.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { z, type ZodType } from "zod";
2+
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
23

34
const trimStringPreprocess = (value: unknown) => (typeof value === "string" ? value.trim() : value);
45

56
const trimLowercaseStringPreprocess = (value: unknown) =>
6-
typeof value === "string" ? value.trim().toLowerCase() : value;
7+
normalizeOptionalLowercaseString(value) ?? value;
78

89
export const DeliveryModeFieldSchema = z
910
.preprocess(trimLowercaseStringPreprocess, z.enum(["deliver", "announce", "none", "webhook"]))

src/cron/delivery-plan.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import type { CronFailureDestinationConfig } from "../config/types.cron.js";
2-
import { normalizeOptionalString, normalizeOptionalThreadValue } from "../shared/string-coerce.js";
2+
import {
3+
normalizeLowercaseStringOrEmpty,
4+
normalizeOptionalLowercaseString,
5+
normalizeOptionalString,
6+
normalizeOptionalThreadValue,
7+
} from "../shared/string-coerce.js";
38
import type { CronDelivery, CronDeliveryMode, CronJob, CronMessageChannel } from "./types.js";
49

510
export type CronDeliveryPlan = {
@@ -14,10 +19,7 @@ export type CronDeliveryPlan = {
1419
};
1520

1621
function normalizeChannel(value: unknown): CronMessageChannel | undefined {
17-
if (typeof value !== "string") {
18-
return undefined;
19-
}
20-
const trimmed = value.trim().toLowerCase();
22+
const trimmed = normalizeOptionalLowercaseString(value);
2123
if (!trimmed) {
2224
return undefined;
2325
}
@@ -28,7 +30,8 @@ export function resolveCronDeliveryPlan(job: CronJob): CronDeliveryPlan {
2830
const delivery = job.delivery;
2931
const hasDelivery = delivery && typeof delivery === "object";
3032
const rawMode = hasDelivery ? (delivery as { mode?: unknown }).mode : undefined;
31-
const normalizedMode = typeof rawMode === "string" ? rawMode.trim().toLowerCase() : rawMode;
33+
const normalizedMode =
34+
typeof rawMode === "string" ? normalizeLowercaseStringOrEmpty(rawMode) : rawMode;
3235
const mode =
3336
normalizedMode === "announce"
3437
? "announce"
@@ -97,10 +100,7 @@ export type CronFailureDestinationInput = {
97100
};
98101

99102
function normalizeFailureMode(value: unknown): "announce" | "webhook" | undefined {
100-
if (typeof value !== "string") {
101-
return undefined;
102-
}
103-
const trimmed = value.trim().toLowerCase();
103+
const trimmed = normalizeOptionalLowercaseString(value);
104104
if (trimmed === "announce" || trimmed === "webhook") {
105105
return trimmed;
106106
}

src/cron/normalize.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
import { sanitizeAgentId } from "../routing/session-key.js";
2+
import {
3+
normalizeLowercaseStringOrEmpty,
4+
normalizeOptionalLowercaseString,
5+
} from "../shared/string-coerce.js";
26
import { isRecord } from "../utils.js";
37
import {
48
TimeoutSecondsFieldSchema,
@@ -61,7 +65,7 @@ function normalizeTrimmedStringArray(
6165

6266
function coerceSchedule(schedule: UnknownRecord) {
6367
const next: UnknownRecord = { ...schedule };
64-
const rawKind = typeof schedule.kind === "string" ? schedule.kind.trim().toLowerCase() : "";
68+
const rawKind = normalizeLowercaseStringOrEmpty(schedule.kind);
6569
const kind = rawKind === "at" || rawKind === "every" || rawKind === "cron" ? rawKind : undefined;
6670
const exprRaw = typeof schedule.expr === "string" ? schedule.expr.trim() : "";
6771
const legacyCronRaw = typeof schedule.cron === "string" ? schedule.cron.trim() : "";
@@ -141,7 +145,7 @@ function coerceSchedule(schedule: UnknownRecord) {
141145

142146
function coercePayload(payload: UnknownRecord) {
143147
const next: UnknownRecord = { ...payload };
144-
const kindRaw = typeof next.kind === "string" ? next.kind.trim().toLowerCase() : "";
148+
const kindRaw = normalizeLowercaseStringOrEmpty(next.kind);
145149
if (kindRaw === "agentturn") {
146150
next.kind = "agentTurn";
147151
} else if (kindRaw === "systemevent") {
@@ -316,7 +320,7 @@ function normalizeSessionTarget(raw: unknown) {
316320
return undefined;
317321
}
318322
const trimmed = raw.trim();
319-
const lower = trimmed.toLowerCase();
323+
const lower = normalizeLowercaseStringOrEmpty(trimmed);
320324
if (lower === "main" || lower === "isolated" || lower === "current") {
321325
return lower;
322326
}
@@ -331,7 +335,7 @@ function normalizeWakeMode(raw: unknown) {
331335
if (typeof raw !== "string") {
332336
return undefined;
333337
}
334-
const trimmed = raw.trim().toLowerCase();
338+
const trimmed = normalizeOptionalLowercaseString(raw);
335339
if (trimmed === "now" || trimmed === "next-heartbeat") {
336340
return trimmed;
337341
}
@@ -439,7 +443,7 @@ export function normalizeCronJobInput(
439443
if (typeof enabled === "boolean") {
440444
next.enabled = enabled;
441445
} else if (typeof enabled === "string") {
442-
const trimmed = enabled.trim().toLowerCase();
446+
const trimmed = normalizeOptionalLowercaseString(enabled);
443447
if (trimmed === "true") {
444448
next.enabled = true;
445449
}

src/cron/run-log.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ import fs from "node:fs/promises";
22
import path from "node:path";
33
import { parseByteSize } from "../cli/parse-bytes.js";
44
import type { CronConfig } from "../config/types.cron.js";
5-
import { normalizeOptionalString } from "../shared/string-coerce.js";
5+
import {
6+
normalizeLowercaseStringOrEmpty,
7+
normalizeOptionalString,
8+
} from "../shared/string-coerce.js";
69
import type { CronDeliveryStatus, CronRunStatus, CronRunTelemetry } from "./types.js";
710

811
export type CronRunLogEntry = {
@@ -361,7 +364,7 @@ export async function readCronRunLogEntriesPage(
361364
const raw = await fs.readFile(path.resolve(filePath), "utf-8").catch(() => "");
362365
const statuses = normalizeRunStatuses(opts);
363366
const deliveryStatuses = normalizeDeliveryStatuses(opts);
364-
const query = opts?.query?.trim().toLowerCase() ?? "";
367+
const query = normalizeLowercaseStringOrEmpty(opts?.query);
365368
const sortDir: CronRunLogSortDir = opts?.sortDir === "asc" ? "asc" : "desc";
366369
const all = parseAllRunLogEntries(raw, { jobId: opts?.jobId });
367370
const filtered = filterRunLogEntries(all, {
@@ -394,7 +397,7 @@ export async function readCronRunLogEntriesPageAll(
394397
const limit = Math.max(1, Math.min(200, Math.floor(opts.limit ?? 50)));
395398
const statuses = normalizeRunStatuses(opts);
396399
const deliveryStatuses = normalizeDeliveryStatuses(opts);
397-
const query = opts.query?.trim().toLowerCase() ?? "";
400+
const query = normalizeLowercaseStringOrEmpty(opts.query);
398401
const sortDir: CronRunLogSortDir = opts.sortDir === "asc" ? "asc" : "desc";
399402
const runsDir = path.resolve(path.dirname(path.resolve(opts.storePath)), "runs");
400403
const files = await fs.readdir(runsDir, { withFileTypes: true }).catch(() => []);

src/cron/service/ops.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { enqueueCommandInLane } from "../../process/command-queue.js";
22
import { CommandLane } from "../../process/lanes.js";
3+
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
34
import {
45
completeTaskRunByRunId,
56
createRunningTaskRun,
@@ -220,7 +221,7 @@ function sortJobs(jobs: CronJob[], sortBy: CronJobsSortBy, sortDir: CronSortDir)
220221
export async function listPage(state: CronServiceState, opts?: CronListPageOptions) {
221222
return await locked(state, async () => {
222223
await ensureLoadedForRead(state);
223-
const query = opts?.query?.trim().toLowerCase() ?? "";
224+
const query = normalizeLowercaseStringOrEmpty(opts?.query);
224225
const enabledFilter = resolveEnabledFilter(opts);
225226
const sortBy = opts?.sortBy ?? "nextRunAtMs";
226227
const sortDir = opts?.sortDir ?? "asc";

src/cron/service/timer.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { resolveFailoverReasonFromError } from "../../agents/failover-error.js";
22
import type { CronConfig, CronRetryOn } from "../../config/types.cron.js";
33
import type { HeartbeatRunResult } from "../../infra/heartbeat-wake.js";
44
import { DEFAULT_AGENT_ID } from "../../routing/session-key.js";
5+
import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js";
56
import {
67
completeTaskRunByRunId,
78
createRunningTaskRun,
@@ -262,10 +263,7 @@ function resolveDeliveryStatus(params: { job: CronJob; delivered?: boolean }): C
262263
}
263264

264265
function normalizeCronMessageChannel(input: unknown): CronMessageChannel | undefined {
265-
if (typeof input !== "string") {
266-
return undefined;
267-
}
268-
const channel = input.trim().toLowerCase();
266+
const channel = normalizeOptionalLowercaseString(input);
269267
return channel ? (channel as CronMessageChannel) : undefined;
270268
}
271269

0 commit comments

Comments
 (0)