@automate.ax/catalog 0.64.0 → 0.65.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/triggers/core.d.ts +102 -9
- package/dist/triggers/core.js +119 -9
- package/package.json +1 -1
- package/src/triggers/core.ts +203 -19
package/dist/triggers/core.d.ts
CHANGED
|
@@ -1,44 +1,97 @@
|
|
|
1
1
|
import * as z from "zod/mini";
|
|
2
2
|
export declare const DASHBOARD_RUN_CONFIG_SCHEMA: z.ZodMiniObject<{
|
|
3
3
|
description: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
4
|
-
fields: z.
|
|
4
|
+
fields: z.ZodMiniPrefault<z.ZodMiniArray<z.ZodMiniDiscriminatedUnion<[z.ZodMiniObject<{
|
|
5
|
+
defaultValue: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
5
6
|
maxLength: z.ZodMiniOptional<z.ZodMiniNumberFormat>;
|
|
6
7
|
minLength: z.ZodMiniOptional<z.ZodMiniNumberFormat>;
|
|
7
8
|
placeholder: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
9
|
+
required: z.ZodMiniPrefault<z.ZodMiniBoolean<boolean>>;
|
|
8
10
|
type: z.ZodMiniEnum<{
|
|
9
11
|
email: "email";
|
|
10
12
|
text: "text";
|
|
11
13
|
url: "url";
|
|
14
|
+
phone: "phone";
|
|
12
15
|
textarea: "textarea";
|
|
13
16
|
}>;
|
|
14
17
|
description: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
15
18
|
label: z.ZodMiniString<string>;
|
|
16
|
-
|
|
19
|
+
name: z.ZodMiniString<string>;
|
|
17
20
|
}, z.core.$strip>, z.ZodMiniObject<{
|
|
21
|
+
defaultValue: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
|
|
18
22
|
max: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
|
|
19
23
|
min: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
|
|
20
24
|
placeholder: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
25
|
+
required: z.ZodMiniPrefault<z.ZodMiniBoolean<boolean>>;
|
|
21
26
|
step: z.ZodMiniPrefault<z.ZodMiniNumber<number>>;
|
|
22
27
|
type: z.ZodMiniLiteral<"number">;
|
|
23
28
|
description: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
24
29
|
label: z.ZodMiniString<string>;
|
|
30
|
+
name: z.ZodMiniString<string>;
|
|
31
|
+
}, z.core.$strip>, z.ZodMiniObject<{
|
|
32
|
+
defaultValue: z.ZodMiniOptional<z.iso.ZodMiniISODate>;
|
|
33
|
+
max: z.ZodMiniOptional<z.iso.ZodMiniISODate>;
|
|
34
|
+
min: z.ZodMiniOptional<z.iso.ZodMiniISODate>;
|
|
25
35
|
required: z.ZodMiniPrefault<z.ZodMiniBoolean<boolean>>;
|
|
36
|
+
step: z.ZodMiniPrefault<z.ZodMiniNumberFormat>;
|
|
37
|
+
type: z.ZodMiniLiteral<"date">;
|
|
38
|
+
description: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
39
|
+
label: z.ZodMiniString<string>;
|
|
40
|
+
name: z.ZodMiniString<string>;
|
|
26
41
|
}, z.core.$strip>, z.ZodMiniObject<{
|
|
42
|
+
defaultValue: z.ZodMiniOptional<z.iso.ZodMiniISODateTime>;
|
|
43
|
+
max: z.ZodMiniOptional<z.iso.ZodMiniISODateTime>;
|
|
44
|
+
min: z.ZodMiniOptional<z.iso.ZodMiniISODateTime>;
|
|
45
|
+
required: z.ZodMiniPrefault<z.ZodMiniBoolean<boolean>>;
|
|
46
|
+
step: z.ZodMiniPrefault<z.ZodMiniNumber<number>>;
|
|
47
|
+
type: z.ZodMiniLiteral<"datetime">;
|
|
48
|
+
description: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
49
|
+
label: z.ZodMiniString<string>;
|
|
50
|
+
name: z.ZodMiniString<string>;
|
|
51
|
+
}, z.core.$strip>, z.ZodMiniObject<{
|
|
52
|
+
type: z.ZodMiniLiteral<"select">;
|
|
53
|
+
defaultValue: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
27
54
|
options: z.ZodMiniArray<z.ZodMiniObject<{
|
|
28
55
|
label: z.ZodMiniString<string>;
|
|
29
56
|
value: z.ZodMiniString<string>;
|
|
30
57
|
}, z.core.$strip>>;
|
|
31
58
|
placeholder: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
32
|
-
|
|
59
|
+
required: z.ZodMiniPrefault<z.ZodMiniBoolean<boolean>>;
|
|
33
60
|
description: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
34
61
|
label: z.ZodMiniString<string>;
|
|
62
|
+
name: z.ZodMiniString<string>;
|
|
63
|
+
}, z.core.$strip>, z.ZodMiniObject<{
|
|
64
|
+
type: z.ZodMiniLiteral<"radio">;
|
|
65
|
+
defaultValue: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
66
|
+
options: z.ZodMiniArray<z.ZodMiniObject<{
|
|
67
|
+
label: z.ZodMiniString<string>;
|
|
68
|
+
value: z.ZodMiniString<string>;
|
|
69
|
+
}, z.core.$strip>>;
|
|
70
|
+
placeholder: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
35
71
|
required: z.ZodMiniPrefault<z.ZodMiniBoolean<boolean>>;
|
|
72
|
+
description: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
73
|
+
label: z.ZodMiniString<string>;
|
|
74
|
+
name: z.ZodMiniString<string>;
|
|
36
75
|
}, z.core.$strip>, z.ZodMiniObject<{
|
|
37
|
-
|
|
76
|
+
defaultValue: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
|
|
77
|
+
options: z.ZodMiniArray<z.ZodMiniObject<{
|
|
78
|
+
label: z.ZodMiniString<string>;
|
|
79
|
+
value: z.ZodMiniString<string>;
|
|
80
|
+
}, z.core.$strip>>;
|
|
81
|
+
placeholder: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
82
|
+
required: z.ZodMiniPrefault<z.ZodMiniBoolean<boolean>>;
|
|
83
|
+
type: z.ZodMiniLiteral<"multi-select">;
|
|
38
84
|
description: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
39
85
|
label: z.ZodMiniString<string>;
|
|
86
|
+
name: z.ZodMiniString<string>;
|
|
87
|
+
}, z.core.$strip>, z.ZodMiniObject<{
|
|
88
|
+
defaultValue: z.ZodMiniPrefault<z.ZodMiniBoolean<boolean>>;
|
|
40
89
|
required: z.ZodMiniPrefault<z.ZodMiniBoolean<boolean>>;
|
|
41
|
-
|
|
90
|
+
type: z.ZodMiniLiteral<"checkbox">;
|
|
91
|
+
description: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
92
|
+
label: z.ZodMiniString<string>;
|
|
93
|
+
name: z.ZodMiniString<string>;
|
|
94
|
+
}, z.core.$strip>], "type">>>;
|
|
42
95
|
submitLabel: z.ZodMiniPrefault<z.ZodMiniString<string>>;
|
|
43
96
|
title: z.ZodMiniString<string>;
|
|
44
97
|
}, z.core.$strip>;
|
|
@@ -94,15 +147,19 @@ interface DashboardRunFieldBase {
|
|
|
94
147
|
description?: string;
|
|
95
148
|
/** Visible field label. */
|
|
96
149
|
label: string;
|
|
150
|
+
/** Property name used in submitted trigger data. */
|
|
151
|
+
name: string;
|
|
97
152
|
/** Whether the form must contain a value. Defaults to true. */
|
|
98
153
|
required?: boolean;
|
|
99
154
|
}
|
|
100
155
|
export type DashboardRunField = (DashboardRunFieldBase & {
|
|
156
|
+
defaultValue?: string;
|
|
101
157
|
maxLength?: number;
|
|
102
158
|
minLength?: number;
|
|
103
159
|
placeholder?: string;
|
|
104
|
-
type: "email" | "text" | "textarea" | "url";
|
|
160
|
+
type: "email" | "phone" | "text" | "textarea" | "url";
|
|
105
161
|
}) | (DashboardRunFieldBase & {
|
|
162
|
+
defaultValue?: number;
|
|
106
163
|
max?: number;
|
|
107
164
|
min?: number;
|
|
108
165
|
placeholder?: string;
|
|
@@ -110,6 +167,23 @@ export type DashboardRunField = (DashboardRunFieldBase & {
|
|
|
110
167
|
step?: number;
|
|
111
168
|
type: "number";
|
|
112
169
|
}) | (DashboardRunFieldBase & {
|
|
170
|
+
/** Initial local date in `YYYY-MM-DD` format. */
|
|
171
|
+
defaultValue?: string;
|
|
172
|
+
max?: string;
|
|
173
|
+
min?: string;
|
|
174
|
+
/** Allowed increment in days. Defaults to 1. */
|
|
175
|
+
step?: number;
|
|
176
|
+
type: "date";
|
|
177
|
+
}) | (DashboardRunFieldBase & {
|
|
178
|
+
/** Initial local date and time in `YYYY-MM-DDTHH:mm` format. */
|
|
179
|
+
defaultValue?: string;
|
|
180
|
+
max?: string;
|
|
181
|
+
min?: string;
|
|
182
|
+
/** Allowed increment in seconds. Defaults to 60. */
|
|
183
|
+
step?: number;
|
|
184
|
+
type: "datetime";
|
|
185
|
+
}) | (DashboardRunFieldBase & {
|
|
186
|
+
defaultValue?: string;
|
|
113
187
|
options: readonly {
|
|
114
188
|
label: string;
|
|
115
189
|
value: string;
|
|
@@ -117,13 +191,32 @@ export type DashboardRunField = (DashboardRunFieldBase & {
|
|
|
117
191
|
placeholder?: string;
|
|
118
192
|
type: "select";
|
|
119
193
|
}) | (DashboardRunFieldBase & {
|
|
194
|
+
defaultValue?: string;
|
|
195
|
+
options: readonly {
|
|
196
|
+
label: string;
|
|
197
|
+
value: string;
|
|
198
|
+
}[];
|
|
199
|
+
type: "radio";
|
|
200
|
+
}) | (DashboardRunFieldBase & {
|
|
201
|
+
defaultValue?: readonly string[];
|
|
202
|
+
options: readonly {
|
|
203
|
+
label: string;
|
|
204
|
+
value: string;
|
|
205
|
+
}[];
|
|
206
|
+
placeholder?: string;
|
|
207
|
+
type: "multi-select";
|
|
208
|
+
}) | (DashboardRunFieldBase & {
|
|
209
|
+
/** Initial checked state. Defaults to false. */
|
|
210
|
+
defaultValue?: boolean;
|
|
211
|
+
/** Whether the checkbox must be checked. Defaults to false. */
|
|
212
|
+
required?: boolean;
|
|
120
213
|
type: "checkbox";
|
|
121
214
|
});
|
|
122
|
-
export interface DashboardRunConfig<TFields extends
|
|
215
|
+
export interface DashboardRunConfig<TFields extends readonly DashboardRunField[] = readonly DashboardRunField[]> {
|
|
123
216
|
/** Supporting text shown below the form title. */
|
|
124
217
|
description?: string;
|
|
125
|
-
/**
|
|
126
|
-
fields
|
|
218
|
+
/** Ordered fields. Omit to run immediately. */
|
|
219
|
+
fields?: TFields;
|
|
127
220
|
/** Submit button text. Defaults to "Run". */
|
|
128
221
|
submitLabel?: string;
|
|
129
222
|
/** Form heading. */
|
package/dist/triggers/core.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as z from "zod/mini";
|
|
2
2
|
const MAX_EMAIL_LOCAL_PART_BYTES = 64;
|
|
3
3
|
const EMAIL_SCHEMA = z.email();
|
|
4
|
+
const URL_SCHEMA = z.url();
|
|
4
5
|
const CRON_PRESENTATION_CONFIG_SCHEMA = z.object({
|
|
5
6
|
schedule: z.string(),
|
|
6
7
|
timeZone: z.prefault(z.string(), "UTC"),
|
|
@@ -25,25 +26,48 @@ const FIELD_LENGTH_SCHEMA = z.int().check(z.nonnegative());
|
|
|
25
26
|
const DASHBOARD_RUN_FIELD_BASE_SCHEMA = {
|
|
26
27
|
description: z.optional(FIELD_DESCRIPTION_SCHEMA),
|
|
27
28
|
label: FIELD_LABEL_SCHEMA,
|
|
28
|
-
|
|
29
|
+
name: FIELD_NAME_SCHEMA,
|
|
29
30
|
};
|
|
30
31
|
const DASHBOARD_RUN_TEXT_FIELD_SCHEMA = z.object({
|
|
31
32
|
...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
|
|
33
|
+
defaultValue: z.optional(z.string()),
|
|
32
34
|
maxLength: z.optional(FIELD_LENGTH_SCHEMA),
|
|
33
35
|
minLength: z.optional(FIELD_LENGTH_SCHEMA),
|
|
34
36
|
placeholder: z.optional(z.string()),
|
|
35
|
-
|
|
37
|
+
required: z.prefault(z.boolean(), true),
|
|
38
|
+
type: z.enum(["email", "phone", "text", "textarea", "url"]),
|
|
36
39
|
});
|
|
37
40
|
const DASHBOARD_RUN_NUMBER_FIELD_SCHEMA = z.object({
|
|
38
41
|
...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
|
|
42
|
+
defaultValue: z.optional(z.number()),
|
|
39
43
|
max: z.optional(z.number()),
|
|
40
44
|
min: z.optional(z.number()),
|
|
41
45
|
placeholder: z.optional(z.string()),
|
|
46
|
+
required: z.prefault(z.boolean(), true),
|
|
42
47
|
step: z.prefault(z.number().check(z.positive()), 1),
|
|
43
48
|
type: z.literal("number"),
|
|
44
49
|
});
|
|
45
|
-
const
|
|
50
|
+
const DASHBOARD_RUN_DATE_FIELD_SCHEMA = z.object({
|
|
51
|
+
...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
|
|
52
|
+
defaultValue: z.optional(z.iso.date()),
|
|
53
|
+
max: z.optional(z.iso.date()),
|
|
54
|
+
min: z.optional(z.iso.date()),
|
|
55
|
+
required: z.prefault(z.boolean(), true),
|
|
56
|
+
step: z.prefault(z.int().check(z.positive()), 1),
|
|
57
|
+
type: z.literal("date"),
|
|
58
|
+
});
|
|
59
|
+
const DASHBOARD_RUN_DATETIME_FIELD_SCHEMA = z.object({
|
|
60
|
+
...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
|
|
61
|
+
defaultValue: z.optional(z.iso.datetime({ local: true })),
|
|
62
|
+
max: z.optional(z.iso.datetime({ local: true })),
|
|
63
|
+
min: z.optional(z.iso.datetime({ local: true })),
|
|
64
|
+
required: z.prefault(z.boolean(), true),
|
|
65
|
+
step: z.prefault(z.number().check(z.positive()), 60),
|
|
66
|
+
type: z.literal("datetime"),
|
|
67
|
+
});
|
|
68
|
+
const DASHBOARD_RUN_CHOICE_FIELD_SCHEMA = {
|
|
46
69
|
...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
|
|
70
|
+
defaultValue: z.optional(FIELD_NAME_SCHEMA),
|
|
47
71
|
options: z
|
|
48
72
|
.array(z.object({
|
|
49
73
|
label: FIELD_LABEL_SCHEMA,
|
|
@@ -51,20 +75,49 @@ const DASHBOARD_RUN_SELECT_FIELD_SCHEMA = z.object({
|
|
|
51
75
|
}))
|
|
52
76
|
.check(z.minLength(1)),
|
|
53
77
|
placeholder: z.optional(z.string()),
|
|
78
|
+
required: z.prefault(z.boolean(), true),
|
|
79
|
+
};
|
|
80
|
+
const DASHBOARD_RUN_SELECT_FIELD_SCHEMA = z.object({
|
|
81
|
+
...DASHBOARD_RUN_CHOICE_FIELD_SCHEMA,
|
|
54
82
|
type: z.literal("select"),
|
|
55
83
|
});
|
|
84
|
+
const DASHBOARD_RUN_RADIO_FIELD_SCHEMA = z.object({
|
|
85
|
+
...DASHBOARD_RUN_CHOICE_FIELD_SCHEMA,
|
|
86
|
+
type: z.literal("radio"),
|
|
87
|
+
});
|
|
88
|
+
const DASHBOARD_RUN_MULTI_SELECT_FIELD_SCHEMA = z.object({
|
|
89
|
+
...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
|
|
90
|
+
defaultValue: z.optional(z.array(FIELD_NAME_SCHEMA)),
|
|
91
|
+
options: z
|
|
92
|
+
.array(z.object({
|
|
93
|
+
label: FIELD_LABEL_SCHEMA,
|
|
94
|
+
value: FIELD_NAME_SCHEMA,
|
|
95
|
+
}))
|
|
96
|
+
.check(z.minLength(1)),
|
|
97
|
+
placeholder: z.optional(z.string()),
|
|
98
|
+
required: z.prefault(z.boolean(), true),
|
|
99
|
+
type: z.literal("multi-select"),
|
|
100
|
+
});
|
|
56
101
|
const DASHBOARD_RUN_CHECKBOX_FIELD_SCHEMA = z.object({
|
|
57
102
|
...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
|
|
103
|
+
defaultValue: z.prefault(z.boolean(), false),
|
|
104
|
+
required: z.prefault(z.boolean(), false),
|
|
58
105
|
type: z.literal("checkbox"),
|
|
59
106
|
});
|
|
107
|
+
const DASHBOARD_RUN_FIELD_SCHEMA = z.discriminatedUnion("type", [
|
|
108
|
+
DASHBOARD_RUN_TEXT_FIELD_SCHEMA,
|
|
109
|
+
DASHBOARD_RUN_NUMBER_FIELD_SCHEMA,
|
|
110
|
+
DASHBOARD_RUN_DATE_FIELD_SCHEMA,
|
|
111
|
+
DASHBOARD_RUN_DATETIME_FIELD_SCHEMA,
|
|
112
|
+
DASHBOARD_RUN_SELECT_FIELD_SCHEMA,
|
|
113
|
+
DASHBOARD_RUN_RADIO_FIELD_SCHEMA,
|
|
114
|
+
DASHBOARD_RUN_MULTI_SELECT_FIELD_SCHEMA,
|
|
115
|
+
DASHBOARD_RUN_CHECKBOX_FIELD_SCHEMA,
|
|
116
|
+
]);
|
|
117
|
+
const DASHBOARD_RUN_FIELDS_SCHEMA = z.array(DASHBOARD_RUN_FIELD_SCHEMA).check(z.refine((fields) => new Set(fields.map((field) => field.name)).size === fields.length, "Dashboard run field names must be unique."), z.refine((fields) => fields.every(isDashboardRunFieldDefaultValid), "Dashboard run field defaults must satisfy their field constraints."));
|
|
60
118
|
export const DASHBOARD_RUN_CONFIG_SCHEMA = z.object({
|
|
61
119
|
description: z.optional(FIELD_DESCRIPTION_SCHEMA),
|
|
62
|
-
fields: z.
|
|
63
|
-
DASHBOARD_RUN_TEXT_FIELD_SCHEMA,
|
|
64
|
-
DASHBOARD_RUN_NUMBER_FIELD_SCHEMA,
|
|
65
|
-
DASHBOARD_RUN_SELECT_FIELD_SCHEMA,
|
|
66
|
-
DASHBOARD_RUN_CHECKBOX_FIELD_SCHEMA,
|
|
67
|
-
])),
|
|
120
|
+
fields: z.prefault(DASHBOARD_RUN_FIELDS_SCHEMA, []),
|
|
68
121
|
submitLabel: z.prefault(z.string().check(z.trim(), z.minLength(1), z.maxLength(100)), "Run"),
|
|
69
122
|
title: z.string().check(z.trim(), z.minLength(1), z.maxLength(255)),
|
|
70
123
|
});
|
|
@@ -212,6 +265,63 @@ export function getDashboardRunEndpointKey(options) {
|
|
|
212
265
|
options.hookSlot,
|
|
213
266
|
].join(".")}`;
|
|
214
267
|
}
|
|
268
|
+
/**
|
|
269
|
+
* Checks a configured default against the same constraints as submitted data.
|
|
270
|
+
*
|
|
271
|
+
* @param field - Field definition to validate.
|
|
272
|
+
*/
|
|
273
|
+
function isDashboardRunFieldDefaultValid(field) {
|
|
274
|
+
if (field.type === "checkbox" || field.defaultValue === undefined)
|
|
275
|
+
return true;
|
|
276
|
+
if (field.type === "multi-select") {
|
|
277
|
+
if (field.required !== false && field.defaultValue.length === 0)
|
|
278
|
+
return false;
|
|
279
|
+
return field.defaultValue.every((value) => field.options.some((option) => option.value === value));
|
|
280
|
+
}
|
|
281
|
+
if (field.type === "radio" || field.type === "select") {
|
|
282
|
+
return field.options.some((option) => option.value === field.defaultValue);
|
|
283
|
+
}
|
|
284
|
+
if (field.type === "number") {
|
|
285
|
+
return ((field.min === undefined || field.defaultValue >= field.min) &&
|
|
286
|
+
(field.max === undefined || field.defaultValue <= field.max) &&
|
|
287
|
+
!isDashboardRunStepMismatch(field.defaultValue, field.min ?? field.defaultValue, field.step ?? 1));
|
|
288
|
+
}
|
|
289
|
+
if (field.type === "date" || field.type === "datetime") {
|
|
290
|
+
const defaultValue = parseDashboardRunDateValue(field.type, field.defaultValue);
|
|
291
|
+
return ((field.min === undefined ||
|
|
292
|
+
defaultValue >= parseDashboardRunDateValue(field.type, field.min)) &&
|
|
293
|
+
(field.max === undefined ||
|
|
294
|
+
defaultValue <= parseDashboardRunDateValue(field.type, field.max)) &&
|
|
295
|
+
!isDashboardRunStepMismatch(defaultValue, parseDashboardRunDateValue(field.type, field.min ?? field.defaultValue), (field.step ?? (field.type === "date" ? 1 : 60)) *
|
|
296
|
+
(field.type === "date" ? 86_400_000 : 1_000)));
|
|
297
|
+
}
|
|
298
|
+
const defaultValue = field.defaultValue.trim();
|
|
299
|
+
return ((defaultValue.length > 0 || field.required === false) &&
|
|
300
|
+
(field.minLength === undefined || defaultValue.length >= field.minLength) &&
|
|
301
|
+
(field.maxLength === undefined || defaultValue.length <= field.maxLength) &&
|
|
302
|
+
(field.type !== "email" || EMAIL_SCHEMA.safeParse(defaultValue).success) &&
|
|
303
|
+
(field.type !== "url" || URL_SCHEMA.safeParse(defaultValue).success));
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Checks whether a value falls outside an allowed step interval.
|
|
307
|
+
*
|
|
308
|
+
* @param value - Configured default value.
|
|
309
|
+
* @param base - Value from which step intervals begin.
|
|
310
|
+
* @param step - Allowed interval size.
|
|
311
|
+
*/
|
|
312
|
+
function isDashboardRunStepMismatch(value, base, step) {
|
|
313
|
+
const intervals = (value - base) / step;
|
|
314
|
+
return Math.abs(intervals - Math.round(intervals)) > 1e-9;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Converts a validated local date or date-time string to a UTC number.
|
|
318
|
+
*
|
|
319
|
+
* @param type - Temporal field type.
|
|
320
|
+
* @param value - Local ISO value to convert.
|
|
321
|
+
*/
|
|
322
|
+
function parseDashboardRunDateValue(type, value) {
|
|
323
|
+
return Date.parse(type === "date" ? `${value}T00:00:00Z` : `${value}Z`);
|
|
324
|
+
}
|
|
215
325
|
/**
|
|
216
326
|
* Removes the redundant TypeID prefix from an address router.
|
|
217
327
|
*
|
package/package.json
CHANGED
package/src/triggers/core.ts
CHANGED
|
@@ -3,6 +3,7 @@ import * as z from "zod/mini"
|
|
|
3
3
|
|
|
4
4
|
const MAX_EMAIL_LOCAL_PART_BYTES = 64
|
|
5
5
|
const EMAIL_SCHEMA = z.email()
|
|
6
|
+
const URL_SCHEMA = z.url()
|
|
6
7
|
const CRON_PRESENTATION_CONFIG_SCHEMA = z.object({
|
|
7
8
|
schedule: z.string(),
|
|
8
9
|
timeZone: z.prefault(z.string(), "UTC"),
|
|
@@ -27,25 +28,48 @@ const FIELD_LENGTH_SCHEMA = z.int().check(z.nonnegative())
|
|
|
27
28
|
const DASHBOARD_RUN_FIELD_BASE_SCHEMA = {
|
|
28
29
|
description: z.optional(FIELD_DESCRIPTION_SCHEMA),
|
|
29
30
|
label: FIELD_LABEL_SCHEMA,
|
|
30
|
-
|
|
31
|
+
name: FIELD_NAME_SCHEMA,
|
|
31
32
|
}
|
|
32
33
|
const DASHBOARD_RUN_TEXT_FIELD_SCHEMA = z.object({
|
|
33
34
|
...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
|
|
35
|
+
defaultValue: z.optional(z.string()),
|
|
34
36
|
maxLength: z.optional(FIELD_LENGTH_SCHEMA),
|
|
35
37
|
minLength: z.optional(FIELD_LENGTH_SCHEMA),
|
|
36
38
|
placeholder: z.optional(z.string()),
|
|
37
|
-
|
|
39
|
+
required: z.prefault(z.boolean(), true),
|
|
40
|
+
type: z.enum(["email", "phone", "text", "textarea", "url"]),
|
|
38
41
|
})
|
|
39
42
|
const DASHBOARD_RUN_NUMBER_FIELD_SCHEMA = z.object({
|
|
40
43
|
...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
|
|
44
|
+
defaultValue: z.optional(z.number()),
|
|
41
45
|
max: z.optional(z.number()),
|
|
42
46
|
min: z.optional(z.number()),
|
|
43
47
|
placeholder: z.optional(z.string()),
|
|
48
|
+
required: z.prefault(z.boolean(), true),
|
|
44
49
|
step: z.prefault(z.number().check(z.positive()), 1),
|
|
45
50
|
type: z.literal("number"),
|
|
46
51
|
})
|
|
47
|
-
const
|
|
52
|
+
const DASHBOARD_RUN_DATE_FIELD_SCHEMA = z.object({
|
|
53
|
+
...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
|
|
54
|
+
defaultValue: z.optional(z.iso.date()),
|
|
55
|
+
max: z.optional(z.iso.date()),
|
|
56
|
+
min: z.optional(z.iso.date()),
|
|
57
|
+
required: z.prefault(z.boolean(), true),
|
|
58
|
+
step: z.prefault(z.int().check(z.positive()), 1),
|
|
59
|
+
type: z.literal("date"),
|
|
60
|
+
})
|
|
61
|
+
const DASHBOARD_RUN_DATETIME_FIELD_SCHEMA = z.object({
|
|
62
|
+
...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
|
|
63
|
+
defaultValue: z.optional(z.iso.datetime({ local: true })),
|
|
64
|
+
max: z.optional(z.iso.datetime({ local: true })),
|
|
65
|
+
min: z.optional(z.iso.datetime({ local: true })),
|
|
66
|
+
required: z.prefault(z.boolean(), true),
|
|
67
|
+
step: z.prefault(z.number().check(z.positive()), 60),
|
|
68
|
+
type: z.literal("datetime"),
|
|
69
|
+
})
|
|
70
|
+
const DASHBOARD_RUN_CHOICE_FIELD_SCHEMA = {
|
|
48
71
|
...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
|
|
72
|
+
defaultValue: z.optional(FIELD_NAME_SCHEMA),
|
|
49
73
|
options: z
|
|
50
74
|
.array(
|
|
51
75
|
z.object({
|
|
@@ -55,24 +79,62 @@ const DASHBOARD_RUN_SELECT_FIELD_SCHEMA = z.object({
|
|
|
55
79
|
)
|
|
56
80
|
.check(z.minLength(1)),
|
|
57
81
|
placeholder: z.optional(z.string()),
|
|
82
|
+
required: z.prefault(z.boolean(), true),
|
|
83
|
+
}
|
|
84
|
+
const DASHBOARD_RUN_SELECT_FIELD_SCHEMA = z.object({
|
|
85
|
+
...DASHBOARD_RUN_CHOICE_FIELD_SCHEMA,
|
|
58
86
|
type: z.literal("select"),
|
|
59
87
|
})
|
|
88
|
+
const DASHBOARD_RUN_RADIO_FIELD_SCHEMA = z.object({
|
|
89
|
+
...DASHBOARD_RUN_CHOICE_FIELD_SCHEMA,
|
|
90
|
+
type: z.literal("radio"),
|
|
91
|
+
})
|
|
92
|
+
const DASHBOARD_RUN_MULTI_SELECT_FIELD_SCHEMA = z.object({
|
|
93
|
+
...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
|
|
94
|
+
defaultValue: z.optional(z.array(FIELD_NAME_SCHEMA)),
|
|
95
|
+
options: z
|
|
96
|
+
.array(
|
|
97
|
+
z.object({
|
|
98
|
+
label: FIELD_LABEL_SCHEMA,
|
|
99
|
+
value: FIELD_NAME_SCHEMA,
|
|
100
|
+
}),
|
|
101
|
+
)
|
|
102
|
+
.check(z.minLength(1)),
|
|
103
|
+
placeholder: z.optional(z.string()),
|
|
104
|
+
required: z.prefault(z.boolean(), true),
|
|
105
|
+
type: z.literal("multi-select"),
|
|
106
|
+
})
|
|
60
107
|
const DASHBOARD_RUN_CHECKBOX_FIELD_SCHEMA = z.object({
|
|
61
108
|
...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
|
|
109
|
+
defaultValue: z.prefault(z.boolean(), false),
|
|
110
|
+
required: z.prefault(z.boolean(), false),
|
|
62
111
|
type: z.literal("checkbox"),
|
|
63
112
|
})
|
|
113
|
+
const DASHBOARD_RUN_FIELD_SCHEMA = z.discriminatedUnion("type", [
|
|
114
|
+
DASHBOARD_RUN_TEXT_FIELD_SCHEMA,
|
|
115
|
+
DASHBOARD_RUN_NUMBER_FIELD_SCHEMA,
|
|
116
|
+
DASHBOARD_RUN_DATE_FIELD_SCHEMA,
|
|
117
|
+
DASHBOARD_RUN_DATETIME_FIELD_SCHEMA,
|
|
118
|
+
DASHBOARD_RUN_SELECT_FIELD_SCHEMA,
|
|
119
|
+
DASHBOARD_RUN_RADIO_FIELD_SCHEMA,
|
|
120
|
+
DASHBOARD_RUN_MULTI_SELECT_FIELD_SCHEMA,
|
|
121
|
+
DASHBOARD_RUN_CHECKBOX_FIELD_SCHEMA,
|
|
122
|
+
])
|
|
123
|
+
const DASHBOARD_RUN_FIELDS_SCHEMA = z.array(DASHBOARD_RUN_FIELD_SCHEMA).check(
|
|
124
|
+
z.refine(
|
|
125
|
+
(fields) =>
|
|
126
|
+
new Set(fields.map((field) => field.name)).size === fields.length,
|
|
127
|
+
"Dashboard run field names must be unique.",
|
|
128
|
+
),
|
|
129
|
+
z.refine(
|
|
130
|
+
(fields) => fields.every(isDashboardRunFieldDefaultValid),
|
|
131
|
+
"Dashboard run field defaults must satisfy their field constraints.",
|
|
132
|
+
),
|
|
133
|
+
)
|
|
64
134
|
|
|
65
135
|
export const DASHBOARD_RUN_CONFIG_SCHEMA = z.object({
|
|
66
136
|
description: z.optional(FIELD_DESCRIPTION_SCHEMA),
|
|
67
|
-
fields: z.
|
|
68
|
-
FIELD_NAME_SCHEMA,
|
|
69
|
-
z.discriminatedUnion("type", [
|
|
70
|
-
DASHBOARD_RUN_TEXT_FIELD_SCHEMA,
|
|
71
|
-
DASHBOARD_RUN_NUMBER_FIELD_SCHEMA,
|
|
72
|
-
DASHBOARD_RUN_SELECT_FIELD_SCHEMA,
|
|
73
|
-
DASHBOARD_RUN_CHECKBOX_FIELD_SCHEMA,
|
|
74
|
-
]),
|
|
75
|
-
),
|
|
137
|
+
fields: z.prefault(DASHBOARD_RUN_FIELDS_SCHEMA, []),
|
|
76
138
|
submitLabel: z.prefault(
|
|
77
139
|
z.string().check(z.trim(), z.minLength(1), z.maxLength(100)),
|
|
78
140
|
"Run",
|
|
@@ -163,18 +225,23 @@ interface DashboardRunFieldBase {
|
|
|
163
225
|
/** Visible field label. */
|
|
164
226
|
label: string
|
|
165
227
|
|
|
228
|
+
/** Property name used in submitted trigger data. */
|
|
229
|
+
name: string
|
|
230
|
+
|
|
166
231
|
/** Whether the form must contain a value. Defaults to true. */
|
|
167
232
|
required?: boolean
|
|
168
233
|
}
|
|
169
234
|
|
|
170
235
|
export type DashboardRunField =
|
|
171
236
|
| (DashboardRunFieldBase & {
|
|
237
|
+
defaultValue?: string
|
|
172
238
|
maxLength?: number
|
|
173
239
|
minLength?: number
|
|
174
240
|
placeholder?: string
|
|
175
|
-
type: "email" | "text" | "textarea" | "url"
|
|
241
|
+
type: "email" | "phone" | "text" | "textarea" | "url"
|
|
176
242
|
})
|
|
177
243
|
| (DashboardRunFieldBase & {
|
|
244
|
+
defaultValue?: number
|
|
178
245
|
max?: number
|
|
179
246
|
min?: number
|
|
180
247
|
placeholder?: string
|
|
@@ -184,25 +251,59 @@ export type DashboardRunField =
|
|
|
184
251
|
type: "number"
|
|
185
252
|
})
|
|
186
253
|
| (DashboardRunFieldBase & {
|
|
254
|
+
/** Initial local date in `YYYY-MM-DD` format. */
|
|
255
|
+
defaultValue?: string
|
|
256
|
+
max?: string
|
|
257
|
+
min?: string
|
|
258
|
+
|
|
259
|
+
/** Allowed increment in days. Defaults to 1. */
|
|
260
|
+
step?: number
|
|
261
|
+
type: "date"
|
|
262
|
+
})
|
|
263
|
+
| (DashboardRunFieldBase & {
|
|
264
|
+
/** Initial local date and time in `YYYY-MM-DDTHH:mm` format. */
|
|
265
|
+
defaultValue?: string
|
|
266
|
+
max?: string
|
|
267
|
+
min?: string
|
|
268
|
+
|
|
269
|
+
/** Allowed increment in seconds. Defaults to 60. */
|
|
270
|
+
step?: number
|
|
271
|
+
type: "datetime"
|
|
272
|
+
})
|
|
273
|
+
| (DashboardRunFieldBase & {
|
|
274
|
+
defaultValue?: string
|
|
187
275
|
options: readonly { label: string; value: string }[]
|
|
188
276
|
placeholder?: string
|
|
189
277
|
type: "select"
|
|
190
278
|
})
|
|
191
279
|
| (DashboardRunFieldBase & {
|
|
280
|
+
defaultValue?: string
|
|
281
|
+
options: readonly { label: string; value: string }[]
|
|
282
|
+
type: "radio"
|
|
283
|
+
})
|
|
284
|
+
| (DashboardRunFieldBase & {
|
|
285
|
+
defaultValue?: readonly string[]
|
|
286
|
+
options: readonly { label: string; value: string }[]
|
|
287
|
+
placeholder?: string
|
|
288
|
+
type: "multi-select"
|
|
289
|
+
})
|
|
290
|
+
| (DashboardRunFieldBase & {
|
|
291
|
+
/** Initial checked state. Defaults to false. */
|
|
292
|
+
defaultValue?: boolean
|
|
293
|
+
|
|
294
|
+
/** Whether the checkbox must be checked. Defaults to false. */
|
|
295
|
+
required?: boolean
|
|
192
296
|
type: "checkbox"
|
|
193
297
|
})
|
|
194
298
|
|
|
195
299
|
export interface DashboardRunConfig<
|
|
196
|
-
TFields extends
|
|
197
|
-
string,
|
|
198
|
-
DashboardRunField
|
|
199
|
-
>,
|
|
300
|
+
TFields extends readonly DashboardRunField[] = readonly DashboardRunField[],
|
|
200
301
|
> {
|
|
201
302
|
/** Supporting text shown below the form title. */
|
|
202
303
|
description?: string
|
|
203
304
|
|
|
204
|
-
/**
|
|
205
|
-
fields
|
|
305
|
+
/** Ordered fields. Omit to run immediately. */
|
|
306
|
+
fields?: TFields
|
|
206
307
|
|
|
207
308
|
/** Submit button text. Defaults to "Run". */
|
|
208
309
|
submitLabel?: string
|
|
@@ -332,6 +433,89 @@ export function getDashboardRunEndpointKey(
|
|
|
332
433
|
].join(".")}`
|
|
333
434
|
}
|
|
334
435
|
|
|
436
|
+
/**
|
|
437
|
+
* Checks a configured default against the same constraints as submitted data.
|
|
438
|
+
*
|
|
439
|
+
* @param field - Field definition to validate.
|
|
440
|
+
*/
|
|
441
|
+
function isDashboardRunFieldDefaultValid(field: DashboardRunField) {
|
|
442
|
+
if (field.type === "checkbox" || field.defaultValue === undefined) return true
|
|
443
|
+
|
|
444
|
+
if (field.type === "multi-select") {
|
|
445
|
+
if (field.required !== false && field.defaultValue.length === 0)
|
|
446
|
+
return false
|
|
447
|
+
return field.defaultValue.every((value) =>
|
|
448
|
+
field.options.some((option) => option.value === value),
|
|
449
|
+
)
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
if (field.type === "radio" || field.type === "select") {
|
|
453
|
+
return field.options.some((option) => option.value === field.defaultValue)
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (field.type === "number") {
|
|
457
|
+
return (
|
|
458
|
+
(field.min === undefined || field.defaultValue >= field.min) &&
|
|
459
|
+
(field.max === undefined || field.defaultValue <= field.max) &&
|
|
460
|
+
!isDashboardRunStepMismatch(
|
|
461
|
+
field.defaultValue,
|
|
462
|
+
field.min ?? field.defaultValue,
|
|
463
|
+
field.step ?? 1,
|
|
464
|
+
)
|
|
465
|
+
)
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
if (field.type === "date" || field.type === "datetime") {
|
|
469
|
+
const defaultValue = parseDashboardRunDateValue(
|
|
470
|
+
field.type,
|
|
471
|
+
field.defaultValue,
|
|
472
|
+
)
|
|
473
|
+
return (
|
|
474
|
+
(field.min === undefined ||
|
|
475
|
+
defaultValue >= parseDashboardRunDateValue(field.type, field.min)) &&
|
|
476
|
+
(field.max === undefined ||
|
|
477
|
+
defaultValue <= parseDashboardRunDateValue(field.type, field.max)) &&
|
|
478
|
+
!isDashboardRunStepMismatch(
|
|
479
|
+
defaultValue,
|
|
480
|
+
parseDashboardRunDateValue(field.type, field.min ?? field.defaultValue),
|
|
481
|
+
(field.step ?? (field.type === "date" ? 1 : 60)) *
|
|
482
|
+
(field.type === "date" ? 86_400_000 : 1_000),
|
|
483
|
+
)
|
|
484
|
+
)
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const defaultValue = field.defaultValue.trim()
|
|
488
|
+
return (
|
|
489
|
+
(defaultValue.length > 0 || field.required === false) &&
|
|
490
|
+
(field.minLength === undefined || defaultValue.length >= field.minLength) &&
|
|
491
|
+
(field.maxLength === undefined || defaultValue.length <= field.maxLength) &&
|
|
492
|
+
(field.type !== "email" || EMAIL_SCHEMA.safeParse(defaultValue).success) &&
|
|
493
|
+
(field.type !== "url" || URL_SCHEMA.safeParse(defaultValue).success)
|
|
494
|
+
)
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Checks whether a value falls outside an allowed step interval.
|
|
499
|
+
*
|
|
500
|
+
* @param value - Configured default value.
|
|
501
|
+
* @param base - Value from which step intervals begin.
|
|
502
|
+
* @param step - Allowed interval size.
|
|
503
|
+
*/
|
|
504
|
+
function isDashboardRunStepMismatch(value: number, base: number, step: number) {
|
|
505
|
+
const intervals = (value - base) / step
|
|
506
|
+
return Math.abs(intervals - Math.round(intervals)) > 1e-9
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Converts a validated local date or date-time string to a UTC number.
|
|
511
|
+
*
|
|
512
|
+
* @param type - Temporal field type.
|
|
513
|
+
* @param value - Local ISO value to convert.
|
|
514
|
+
*/
|
|
515
|
+
function parseDashboardRunDateValue(type: "date" | "datetime", value: string) {
|
|
516
|
+
return Date.parse(type === "date" ? `${value}T00:00:00Z` : `${value}Z`)
|
|
517
|
+
}
|
|
518
|
+
|
|
335
519
|
/**
|
|
336
520
|
* Removes the redundant TypeID prefix from an address router.
|
|
337
521
|
*
|