@hachej/boring-automation 0.1.71 → 0.1.80

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.
@@ -6,14 +6,22 @@ declare const BORING_AUTOMATION_ROUTE_PREFIX = "/api/v1/boring-automation";
6
6
 
7
7
  declare const BORING_AUTOMATION_ERROR_CODES: {
8
8
  readonly INVALID_BODY: "BORING_AUTOMATION_INVALID_BODY";
9
+ readonly INVALID_CRON: "BORING_AUTOMATION_INVALID_CRON";
10
+ readonly INVALID_TIMEZONE: "BORING_AUTOMATION_INVALID_TIMEZONE";
11
+ readonly INVALID_MODEL: "BORING_AUTOMATION_INVALID_MODEL";
9
12
  readonly AUTOMATION_NOT_FOUND: "BORING_AUTOMATION_NOT_FOUND";
10
13
  readonly RUN_NOT_FOUND: "BORING_AUTOMATION_RUN_NOT_FOUND";
14
+ readonly RUN_ALREADY_ACTIVE: "BORING_AUTOMATION_RUN_ALREADY_ACTIVE";
15
+ readonly RUN_ALREADY_RECORDED: "BORING_AUTOMATION_RUN_ALREADY_RECORDED";
16
+ readonly RUN_EXECUTOR_UNAVAILABLE: "BORING_AUTOMATION_RUN_EXECUTOR_UNAVAILABLE";
17
+ readonly TRIGGER_FORBIDDEN: "BORING_AUTOMATION_TRIGGER_FORBIDDEN";
18
+ readonly RUN_FAILED: "BORING_AUTOMATION_RUN_FAILED";
11
19
  };
12
20
  type BoringAutomationErrorCode = typeof BORING_AUTOMATION_ERROR_CODES[keyof typeof BORING_AUTOMATION_ERROR_CODES];
13
21
 
14
22
  declare const AutomationRunStatusSchema: z.ZodEnum<["queued", "running", "succeeded", "failed", "cancelled"]>;
15
23
  declare const AutomationRunTriggerSchema: z.ZodEnum<["manual", "scheduled"]>;
16
- declare const AutomationCreateSchema: z.ZodObject<{
24
+ declare const AutomationCreateSchema: z.ZodEffects<z.ZodObject<{
17
25
  title: z.ZodString;
18
26
  enabled: z.ZodOptional<z.ZodBoolean>;
19
27
  cron: z.ZodString;
@@ -34,8 +42,22 @@ declare const AutomationCreateSchema: z.ZodObject<{
34
42
  model: string;
35
43
  enabled?: boolean | undefined;
36
44
  prompt?: string | undefined;
45
+ }>, {
46
+ title: string;
47
+ cron: string;
48
+ timezone: string;
49
+ model: string;
50
+ enabled?: boolean | undefined;
51
+ prompt?: string | undefined;
52
+ }, {
53
+ title: string;
54
+ cron: string;
55
+ timezone: string;
56
+ model: string;
57
+ enabled?: boolean | undefined;
58
+ prompt?: string | undefined;
37
59
  }>;
38
- declare const AutomationPatchSchema: z.ZodEffects<z.ZodObject<{
60
+ declare const AutomationPatchSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
39
61
  title: z.ZodOptional<z.ZodString>;
40
62
  enabled: z.ZodOptional<z.ZodBoolean>;
41
63
  cron: z.ZodOptional<z.ZodString>;
@@ -43,27 +65,39 @@ declare const AutomationPatchSchema: z.ZodEffects<z.ZodObject<{
43
65
  model: z.ZodOptional<z.ZodString>;
44
66
  }, "strict", z.ZodTypeAny, {
45
67
  title?: string | undefined;
46
- enabled?: boolean | undefined;
47
68
  cron?: string | undefined;
48
69
  timezone?: string | undefined;
70
+ enabled?: boolean | undefined;
49
71
  model?: string | undefined;
50
72
  }, {
51
73
  title?: string | undefined;
52
- enabled?: boolean | undefined;
53
74
  cron?: string | undefined;
54
75
  timezone?: string | undefined;
76
+ enabled?: boolean | undefined;
55
77
  model?: string | undefined;
56
78
  }>, {
57
79
  title?: string | undefined;
58
- enabled?: boolean | undefined;
59
80
  cron?: string | undefined;
60
81
  timezone?: string | undefined;
82
+ enabled?: boolean | undefined;
61
83
  model?: string | undefined;
62
84
  }, {
63
85
  title?: string | undefined;
86
+ cron?: string | undefined;
87
+ timezone?: string | undefined;
88
+ enabled?: boolean | undefined;
89
+ model?: string | undefined;
90
+ }>, {
91
+ title?: string | undefined;
92
+ cron?: string | undefined;
93
+ timezone?: string | undefined;
64
94
  enabled?: boolean | undefined;
95
+ model?: string | undefined;
96
+ }, {
97
+ title?: string | undefined;
65
98
  cron?: string | undefined;
66
99
  timezone?: string | undefined;
100
+ enabled?: boolean | undefined;
67
101
  model?: string | undefined;
68
102
  }>;
69
103
  declare const PromptUpdateSchema: z.ZodObject<{
@@ -73,56 +107,31 @@ declare const PromptUpdateSchema: z.ZodObject<{
73
107
  }, {
74
108
  prompt: string;
75
109
  }>;
76
- declare const AutomationRunCreateSchema: z.ZodObject<{
110
+ declare const AutomationRunBeginSchema: z.ZodObject<{
77
111
  automationId: z.ZodString;
78
- sessionId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
79
- status: z.ZodOptional<z.ZodEnum<["queued", "running", "succeeded", "failed", "cancelled"]>>;
80
112
  trigger: z.ZodEnum<["manual", "scheduled"]>;
81
113
  scheduledFor: z.ZodOptional<z.ZodNullable<z.ZodString>>;
82
- startedAt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
83
- completedAt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
84
- durationMs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
85
- inputTokens: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
86
- outputTokens: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
87
- totalTokens: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
88
114
  promptSnapshot: z.ZodString;
89
115
  modelSnapshot: z.ZodString;
90
- error: z.ZodOptional<z.ZodNullable<z.ZodString>>;
116
+ createdAt: z.ZodOptional<z.ZodString>;
91
117
  }, "strict", z.ZodTypeAny, {
92
118
  automationId: string;
93
119
  trigger: "manual" | "scheduled";
94
120
  promptSnapshot: string;
95
121
  modelSnapshot: string;
96
- error?: string | null | undefined;
97
- status?: "queued" | "running" | "succeeded" | "failed" | "cancelled" | undefined;
98
- sessionId?: string | null | undefined;
99
122
  scheduledFor?: string | null | undefined;
100
- startedAt?: string | null | undefined;
101
- completedAt?: string | null | undefined;
102
- durationMs?: number | null | undefined;
103
- inputTokens?: number | null | undefined;
104
- outputTokens?: number | null | undefined;
105
- totalTokens?: number | null | undefined;
123
+ createdAt?: string | undefined;
106
124
  }, {
107
125
  automationId: string;
108
126
  trigger: "manual" | "scheduled";
109
127
  promptSnapshot: string;
110
128
  modelSnapshot: string;
111
- error?: string | null | undefined;
112
- status?: "queued" | "running" | "succeeded" | "failed" | "cancelled" | undefined;
113
- sessionId?: string | null | undefined;
114
129
  scheduledFor?: string | null | undefined;
115
- startedAt?: string | null | undefined;
116
- completedAt?: string | null | undefined;
117
- durationMs?: number | null | undefined;
118
- inputTokens?: number | null | undefined;
119
- outputTokens?: number | null | undefined;
120
- totalTokens?: number | null | undefined;
130
+ createdAt?: string | undefined;
121
131
  }>;
122
- declare const AutomationRunPatchSchema: z.ZodEffects<z.ZodObject<{
132
+ declare const AutomationRunLifecyclePatchSchema: z.ZodEffects<z.ZodObject<{
123
133
  sessionId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
124
134
  status: z.ZodOptional<z.ZodEnum<["queued", "running", "succeeded", "failed", "cancelled"]>>;
125
- scheduledFor: z.ZodOptional<z.ZodNullable<z.ZodString>>;
126
135
  startedAt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
127
136
  completedAt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
128
137
  durationMs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
@@ -134,7 +143,6 @@ declare const AutomationRunPatchSchema: z.ZodEffects<z.ZodObject<{
134
143
  error?: string | null | undefined;
135
144
  status?: "queued" | "running" | "succeeded" | "failed" | "cancelled" | undefined;
136
145
  sessionId?: string | null | undefined;
137
- scheduledFor?: string | null | undefined;
138
146
  startedAt?: string | null | undefined;
139
147
  completedAt?: string | null | undefined;
140
148
  durationMs?: number | null | undefined;
@@ -145,7 +153,6 @@ declare const AutomationRunPatchSchema: z.ZodEffects<z.ZodObject<{
145
153
  error?: string | null | undefined;
146
154
  status?: "queued" | "running" | "succeeded" | "failed" | "cancelled" | undefined;
147
155
  sessionId?: string | null | undefined;
148
- scheduledFor?: string | null | undefined;
149
156
  startedAt?: string | null | undefined;
150
157
  completedAt?: string | null | undefined;
151
158
  durationMs?: number | null | undefined;
@@ -156,7 +163,6 @@ declare const AutomationRunPatchSchema: z.ZodEffects<z.ZodObject<{
156
163
  error?: string | null | undefined;
157
164
  status?: "queued" | "running" | "succeeded" | "failed" | "cancelled" | undefined;
158
165
  sessionId?: string | null | undefined;
159
- scheduledFor?: string | null | undefined;
160
166
  startedAt?: string | null | undefined;
161
167
  completedAt?: string | null | undefined;
162
168
  durationMs?: number | null | undefined;
@@ -167,7 +173,6 @@ declare const AutomationRunPatchSchema: z.ZodEffects<z.ZodObject<{
167
173
  error?: string | null | undefined;
168
174
  status?: "queued" | "running" | "succeeded" | "failed" | "cancelled" | undefined;
169
175
  sessionId?: string | null | undefined;
170
- scheduledFor?: string | null | undefined;
171
176
  startedAt?: string | null | undefined;
172
177
  completedAt?: string | null | undefined;
173
178
  durationMs?: number | null | undefined;
@@ -184,8 +189,8 @@ declare const IdParamsSchema: z.ZodObject<{
184
189
  }>;
185
190
  type AutomationCreateInput = z.infer<typeof AutomationCreateSchema>;
186
191
  type AutomationPatchInput = z.infer<typeof AutomationPatchSchema>;
187
- type AutomationRunCreateInput = z.infer<typeof AutomationRunCreateSchema>;
188
- type AutomationRunPatchInput = z.infer<typeof AutomationRunPatchSchema>;
192
+ type AutomationRunBeginInput = z.infer<typeof AutomationRunBeginSchema>;
193
+ type AutomationRunLifecyclePatchInput = z.infer<typeof AutomationRunLifecyclePatchSchema>;
189
194
 
190
195
  type AutomationRunStatus = "queued" | "running" | "succeeded" | "failed" | "cancelled";
191
196
  type AutomationRunTrigger = "manual" | "scheduled";
@@ -234,26 +239,17 @@ interface AutomationRun {
234
239
  createdAt: string;
235
240
  updatedAt: string;
236
241
  }
237
- interface AutomationRunCreate {
242
+ interface AutomationRunBegin {
238
243
  automationId: string;
239
- sessionId?: string | null;
240
- status?: AutomationRunStatus;
241
244
  trigger: AutomationRunTrigger;
242
245
  scheduledFor?: string | null;
243
- startedAt?: string | null;
244
- completedAt?: string | null;
245
- durationMs?: number | null;
246
- inputTokens?: number | null;
247
- outputTokens?: number | null;
248
- totalTokens?: number | null;
249
246
  promptSnapshot: string;
250
247
  modelSnapshot: string;
251
- error?: string | null;
248
+ createdAt?: string;
252
249
  }
253
- interface AutomationRunPatch {
250
+ interface AutomationRunLifecyclePatch {
254
251
  sessionId?: string | null;
255
252
  status?: AutomationRunStatus;
256
- scheduledFor?: string | null;
257
253
  startedAt?: string | null;
258
254
  completedAt?: string | null;
259
255
  durationMs?: number | null;
@@ -263,4 +259,44 @@ interface AutomationRunPatch {
263
259
  error?: string | null;
264
260
  }
265
261
 
266
- export { type Automation, type AutomationCreate, type AutomationCreateInput, AutomationCreateSchema, type AutomationPatch, type AutomationPatchInput, AutomationPatchSchema, type AutomationRun, type AutomationRunCreate, type AutomationRunCreateInput, AutomationRunCreateSchema, type AutomationRunPatch, type AutomationRunPatchInput, AutomationRunPatchSchema, type AutomationRunStatus, AutomationRunStatusSchema, type AutomationRunTrigger, AutomationRunTriggerSchema, BORING_AUTOMATION_ERROR_CODES, BORING_AUTOMATION_PLUGIN_ID, BORING_AUTOMATION_PLUGIN_LABEL, BORING_AUTOMATION_ROUTE_PREFIX, type BoringAutomationErrorCode, IdParamsSchema, PromptUpdateSchema };
262
+ declare const AUTOMATION_SCHEDULE_ERRORS: {
263
+ readonly INVALID_CRON: "Invalid cron schedule. Use exactly five fields, for example 0 9 * * *.";
264
+ readonly INVALID_TIMEZONE: "Invalid timezone. Use a valid IANA timezone, for example UTC or America/New_York.";
265
+ };
266
+ type AutomationScheduleSkipReason = "disabled" | "invalid-cron" | "invalid-timezone" | "not-current-minute" | "duplicate-scheduled-run" | "active-run";
267
+ type AutomationScheduleDueReason = "current-minute-matched";
268
+ interface AutomationScheduleValidationResult {
269
+ ok: boolean;
270
+ errors: Partial<Record<"cron" | "timezone", string>>;
271
+ }
272
+ interface AutomationScheduleDueDecision {
273
+ kind: "due";
274
+ automation: Automation;
275
+ automationId: string;
276
+ scheduledFor: string;
277
+ reason: AutomationScheduleDueReason;
278
+ }
279
+ interface AutomationScheduleSkipDecision {
280
+ kind: "skip";
281
+ automation: Automation;
282
+ automationId: string;
283
+ scheduledFor: string | null;
284
+ reason: AutomationScheduleSkipReason;
285
+ message: string;
286
+ }
287
+ type AutomationScheduleDecision = AutomationScheduleDueDecision | AutomationScheduleSkipDecision;
288
+ interface EvaluateAutomationScheduleInput {
289
+ automations: readonly Automation[];
290
+ runs: readonly AutomationRun[];
291
+ now: Date;
292
+ }
293
+ interface EvaluateAutomationScheduleResult {
294
+ decisions: AutomationScheduleDecision[];
295
+ due: AutomationScheduleDueDecision[];
296
+ }
297
+ declare function validateAutomationSchedule(cron: string, timezone: string): AutomationScheduleValidationResult;
298
+ declare function isValidFiveFieldCron(cron: string): boolean;
299
+ declare function isValidIanaTimeZone(timezone: string): boolean;
300
+ declare function evaluateAutomationSchedule(input: EvaluateAutomationScheduleInput): EvaluateAutomationScheduleResult;
301
+
302
+ export { AUTOMATION_SCHEDULE_ERRORS, type Automation, type AutomationCreate, type AutomationCreateInput, AutomationCreateSchema, type AutomationPatch, type AutomationPatchInput, AutomationPatchSchema, type AutomationRun, type AutomationRunBegin, type AutomationRunBeginInput, AutomationRunBeginSchema, type AutomationRunLifecyclePatch, type AutomationRunLifecyclePatchInput, AutomationRunLifecyclePatchSchema, type AutomationRunStatus, AutomationRunStatusSchema, type AutomationRunTrigger, AutomationRunTriggerSchema, type AutomationScheduleDecision, type AutomationScheduleDueDecision, type AutomationScheduleDueReason, type AutomationScheduleSkipDecision, type AutomationScheduleSkipReason, type AutomationScheduleValidationResult, BORING_AUTOMATION_ERROR_CODES, BORING_AUTOMATION_PLUGIN_ID, BORING_AUTOMATION_PLUGIN_LABEL, BORING_AUTOMATION_ROUTE_PREFIX, type BoringAutomationErrorCode, type EvaluateAutomationScheduleInput, type EvaluateAutomationScheduleResult, IdParamsSchema, PromptUpdateSchema, evaluateAutomationSchedule, isValidFiveFieldCron, isValidIanaTimeZone, validateAutomationSchedule };
@@ -6,12 +6,110 @@ var BORING_AUTOMATION_ROUTE_PREFIX = "/api/v1/boring-automation";
6
6
  // src/shared/error-codes.ts
7
7
  var BORING_AUTOMATION_ERROR_CODES = {
8
8
  INVALID_BODY: "BORING_AUTOMATION_INVALID_BODY",
9
+ INVALID_CRON: "BORING_AUTOMATION_INVALID_CRON",
10
+ INVALID_TIMEZONE: "BORING_AUTOMATION_INVALID_TIMEZONE",
11
+ INVALID_MODEL: "BORING_AUTOMATION_INVALID_MODEL",
9
12
  AUTOMATION_NOT_FOUND: "BORING_AUTOMATION_NOT_FOUND",
10
- RUN_NOT_FOUND: "BORING_AUTOMATION_RUN_NOT_FOUND"
13
+ RUN_NOT_FOUND: "BORING_AUTOMATION_RUN_NOT_FOUND",
14
+ RUN_ALREADY_ACTIVE: "BORING_AUTOMATION_RUN_ALREADY_ACTIVE",
15
+ RUN_ALREADY_RECORDED: "BORING_AUTOMATION_RUN_ALREADY_RECORDED",
16
+ RUN_EXECUTOR_UNAVAILABLE: "BORING_AUTOMATION_RUN_EXECUTOR_UNAVAILABLE",
17
+ TRIGGER_FORBIDDEN: "BORING_AUTOMATION_TRIGGER_FORBIDDEN",
18
+ RUN_FAILED: "BORING_AUTOMATION_RUN_FAILED"
11
19
  };
12
20
 
13
21
  // src/shared/schema.ts
14
22
  import { z } from "zod";
23
+
24
+ // src/shared/schedule.ts
25
+ import { Cron } from "croner";
26
+ var AUTOMATION_SCHEDULE_ERRORS = {
27
+ INVALID_CRON: "Invalid cron schedule. Use exactly five fields, for example 0 9 * * *.",
28
+ INVALID_TIMEZONE: "Invalid timezone. Use a valid IANA timezone, for example UTC or America/New_York."
29
+ };
30
+ function validateAutomationSchedule(cron, timezone) {
31
+ const errors = {};
32
+ if (!isValidFiveFieldCron(cron)) errors.cron = AUTOMATION_SCHEDULE_ERRORS.INVALID_CRON;
33
+ if (!isValidIanaTimeZone(timezone)) errors.timezone = AUTOMATION_SCHEDULE_ERRORS.INVALID_TIMEZONE;
34
+ return { ok: Object.keys(errors).length === 0, errors };
35
+ }
36
+ function isValidFiveFieldCron(cron) {
37
+ const normalized = normalizeSpace(cron);
38
+ if (!normalized || normalized.split(" ").length !== 5) return false;
39
+ try {
40
+ new Cron(normalized);
41
+ return true;
42
+ } catch {
43
+ return false;
44
+ }
45
+ }
46
+ function isValidIanaTimeZone(timezone) {
47
+ const normalized = timezone.trim();
48
+ if (!normalized) return false;
49
+ try {
50
+ const resolved = new Intl.DateTimeFormat("en-US", { timeZone: normalized }).resolvedOptions().timeZone;
51
+ return resolved === "UTC" || resolved.includes("/");
52
+ } catch {
53
+ return false;
54
+ }
55
+ }
56
+ function evaluateAutomationSchedule(input) {
57
+ const now = new Date(input.now);
58
+ const scheduledFor = floorToMinute(now).toISOString();
59
+ const runs = [...input.runs];
60
+ const decisions = input.automations.map((automation) => {
61
+ const validation = validateAutomationSchedule(automation.cron, automation.timezone);
62
+ if (validation.errors.cron) return skip(automation, null, "invalid-cron", validation.errors.cron);
63
+ if (validation.errors.timezone) return skip(automation, null, "invalid-timezone", validation.errors.timezone);
64
+ if (!automation.enabled) return skip(automation, null, "disabled", "Automation is disabled.");
65
+ const cron = new Cron(normalizeSpace(automation.cron), { timezone: automation.timezone.trim() });
66
+ if (!cron.match(new Date(scheduledFor))) {
67
+ return skip(automation, null, "not-current-minute", "Automation is not scheduled for the current minute.");
68
+ }
69
+ if (hasDuplicateScheduledRun(runs, automation.id, scheduledFor)) {
70
+ return skip(automation, scheduledFor, "duplicate-scheduled-run", "A run already exists for this scheduled minute.");
71
+ }
72
+ if (hasActiveRun(runs, automation.id)) {
73
+ return skip(automation, scheduledFor, "active-run", "Automation already has a queued or running run.");
74
+ }
75
+ return {
76
+ kind: "due",
77
+ automation,
78
+ automationId: automation.id,
79
+ scheduledFor,
80
+ reason: "current-minute-matched"
81
+ };
82
+ }).sort(compareScheduleDecisions);
83
+ return { decisions, due: decisions.filter((decision) => decision.kind === "due") };
84
+ }
85
+ function skip(automation, scheduledFor, reason, message) {
86
+ return { kind: "skip", automation, automationId: automation.id, scheduledFor, reason, message };
87
+ }
88
+ function hasDuplicateScheduledRun(runs, automationId, scheduledFor) {
89
+ return runs.some((run) => run.automationId === automationId && run.trigger === "scheduled" && run.scheduledFor === scheduledFor);
90
+ }
91
+ function hasActiveRun(runs, automationId) {
92
+ return runs.some((run) => run.automationId === automationId && (run.status === "queued" || run.status === "running"));
93
+ }
94
+ function floorToMinute(date) {
95
+ const next = new Date(date);
96
+ next.setUTCSeconds(0, 0);
97
+ return next;
98
+ }
99
+ function normalizeSpace(value) {
100
+ return value.trim().replace(/\s+/g, " ");
101
+ }
102
+ function compareScheduleDecisions(a, b) {
103
+ return compareNullableString(a.scheduledFor, b.scheduledFor) || a.automationId.localeCompare(b.automationId);
104
+ }
105
+ function compareNullableString(a, b) {
106
+ if (a === b) return 0;
107
+ if (a === null) return 1;
108
+ if (b === null) return -1;
109
+ return a.localeCompare(b);
110
+ }
111
+
112
+ // src/shared/schema.ts
15
113
  var nonEmptyString = z.string().trim().min(1);
16
114
  var isoString = z.string().datetime({ offset: true });
17
115
  var nonNegativeInteger = z.number().int().nonnegative();
@@ -24,37 +122,32 @@ var AutomationCreateSchema = z.object({
24
122
  timezone: nonEmptyString,
25
123
  model: nonEmptyString,
26
124
  prompt: z.string().optional()
27
- }).strict();
125
+ }).strict().superRefine((value, ctx) => {
126
+ addScheduleIssues(ctx, value);
127
+ });
28
128
  var AutomationPatchSchema = z.object({
29
129
  title: nonEmptyString.optional(),
30
130
  enabled: z.boolean().optional(),
31
131
  cron: nonEmptyString.optional(),
32
132
  timezone: nonEmptyString.optional(),
33
133
  model: nonEmptyString.optional()
34
- }).strict().refine((value) => Object.keys(value).length > 0, "at least one field must be provided");
134
+ }).strict().refine((value) => Object.keys(value).length > 0, "at least one field must be provided").superRefine((value, ctx) => {
135
+ addScheduleIssues(ctx, value);
136
+ });
35
137
  var PromptUpdateSchema = z.object({
36
138
  prompt: z.string()
37
139
  }).strict();
38
- var AutomationRunCreateSchema = z.object({
140
+ var AutomationRunBeginSchema = z.object({
39
141
  automationId: nonEmptyString,
40
- sessionId: nonEmptyString.nullable().optional(),
41
- status: AutomationRunStatusSchema.optional(),
42
142
  trigger: AutomationRunTriggerSchema,
43
143
  scheduledFor: isoString.nullable().optional(),
44
- startedAt: isoString.nullable().optional(),
45
- completedAt: isoString.nullable().optional(),
46
- durationMs: nonNegativeInteger.nullable().optional(),
47
- inputTokens: nonNegativeInteger.nullable().optional(),
48
- outputTokens: nonNegativeInteger.nullable().optional(),
49
- totalTokens: nonNegativeInteger.nullable().optional(),
50
144
  promptSnapshot: z.string(),
51
145
  modelSnapshot: nonEmptyString,
52
- error: z.string().nullable().optional()
146
+ createdAt: isoString.optional()
53
147
  }).strict();
54
- var AutomationRunPatchSchema = z.object({
148
+ var AutomationRunLifecyclePatchSchema = z.object({
55
149
  sessionId: nonEmptyString.nullable().optional(),
56
150
  status: AutomationRunStatusSchema.optional(),
57
- scheduledFor: isoString.nullable().optional(),
58
151
  startedAt: isoString.nullable().optional(),
59
152
  completedAt: isoString.nullable().optional(),
60
153
  durationMs: nonNegativeInteger.nullable().optional(),
@@ -64,11 +157,20 @@ var AutomationRunPatchSchema = z.object({
64
157
  error: z.string().nullable().optional()
65
158
  }).strict().refine((value) => Object.keys(value).length > 0, "at least one field must be provided");
66
159
  var IdParamsSchema = z.object({ id: nonEmptyString });
160
+ function addScheduleIssues(ctx, value) {
161
+ if (value.cron !== void 0 && !isValidFiveFieldCron(value.cron)) {
162
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["cron"], message: AUTOMATION_SCHEDULE_ERRORS.INVALID_CRON });
163
+ }
164
+ if (value.timezone !== void 0 && !isValidIanaTimeZone(value.timezone)) {
165
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["timezone"], message: AUTOMATION_SCHEDULE_ERRORS.INVALID_TIMEZONE });
166
+ }
167
+ }
67
168
  export {
169
+ AUTOMATION_SCHEDULE_ERRORS,
68
170
  AutomationCreateSchema,
69
171
  AutomationPatchSchema,
70
- AutomationRunCreateSchema,
71
- AutomationRunPatchSchema,
172
+ AutomationRunBeginSchema,
173
+ AutomationRunLifecyclePatchSchema,
72
174
  AutomationRunStatusSchema,
73
175
  AutomationRunTriggerSchema,
74
176
  BORING_AUTOMATION_ERROR_CODES,
@@ -76,5 +178,9 @@ export {
76
178
  BORING_AUTOMATION_PLUGIN_LABEL,
77
179
  BORING_AUTOMATION_ROUTE_PREFIX,
78
180
  IdParamsSchema,
79
- PromptUpdateSchema
181
+ PromptUpdateSchema,
182
+ evaluateAutomationSchedule,
183
+ isValidFiveFieldCron,
184
+ isValidIanaTimeZone,
185
+ validateAutomationSchedule
80
186
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hachej/boring-automation",
3
- "version": "0.1.71",
3
+ "version": "0.1.80",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "license": "MIT",
@@ -39,26 +39,20 @@
39
39
  "./package.json": "./package.json"
40
40
  },
41
41
  "sideEffects": false,
42
- "scripts": {
43
- "build": "tsup",
44
- "typecheck": "tsc --noEmit",
45
- "test": "vitest run --no-file-parallelism",
46
- "lint": "pnpm run typecheck",
47
- "clean": "rm -rf dist .tsbuildinfo"
48
- },
49
42
  "peerDependencies": {
50
- "@hachej/boring-workspace": "workspace:*",
51
43
  "fastify": "^5.9.0",
52
44
  "react": "^18.0.0 || ^19.0.0",
53
- "react-dom": "^18.0.0 || ^19.0.0"
45
+ "react-dom": "^18.0.0 || ^19.0.0",
46
+ "@hachej/boring-workspace": "0.1.80"
54
47
  },
55
48
  "dependencies": {
56
- "@hachej/boring-ui-kit": "workspace:*",
49
+ "croner": "^10.0.1",
57
50
  "lucide-react": "^1.21.0",
58
- "zod": "^3.23.0"
51
+ "postgres": "^3.4.7",
52
+ "zod": "^3.23.0",
53
+ "@hachej/boring-ui-kit": "0.1.80"
59
54
  },
60
55
  "devDependencies": {
61
- "@hachej/boring-workspace": "workspace:*",
62
56
  "@testing-library/jest-dom": "^6.9.1",
63
57
  "@testing-library/react": "^16.3.0",
64
58
  "@types/node": "^22.20.0",
@@ -71,11 +65,19 @@
71
65
  "react-dom": "^19.2.7",
72
66
  "tsup": "^8.4.0",
73
67
  "typescript": "~6.0.3",
74
- "vitest": "^4.1.9"
68
+ "vitest": "^4.1.9",
69
+ "@hachej/boring-workspace": "0.1.80"
75
70
  },
76
71
  "peerDependenciesMeta": {
77
72
  "fastify": {
78
73
  "optional": true
79
74
  }
75
+ },
76
+ "scripts": {
77
+ "build": "tsup",
78
+ "typecheck": "tsc --noEmit",
79
+ "test": "vitest run --no-file-parallelism",
80
+ "lint": "pnpm run typecheck",
81
+ "clean": "rm -rf dist .tsbuildinfo"
80
82
  }
81
- }
83
+ }