@automate.ax/catalog 0.63.0 → 0.65.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/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export { airtableService, anthropicService, apolloService, asanaService, brevoService, cerebrasService, cloudflareService, cohereService, deepinfraService, deepseekService, firecrawlService, fireworksService, getIntegrationService, githubService, googleGenaiService, googleService, groqService, huggingfaceService, integrationCatalog, linearService, microsoftService, millionverifierService, mistralService, openaiService, openrouterService, perplexityService, postgresService, resendService, scrapflyService, slackService, tidycalService, togetheraiService, trelloService, vercelAiGatewayService, vercelService, whatsappService, xaiService, type IntegrationServiceId, } from "./catalog.js";
2
2
  export { defineIntegrationCatalog, defineIntegrationService, integrationScope, type IntegrationAccountConnectionOption, type IntegrationAccountRequirement, type IntegrationConnectionDefinition, type IntegrationFormField, type IntegrationScopeRequirement, type IntegrationServiceDefinition, type ScopeRequirementGroup, type TriggerDefinition, type TriggerPresentation, type TriggerPresentationContext, type TriggerPresentationDetail, type TriggerScopePresentation, type TriggerPresentationValue, } from "./types.js";
3
- export { getDashboardRunEndpoint, getDashboardRunEndpointKey, getHttpTriggerEndpoint, getHttpTriggerEndpointKey, DASHBOARD_RUN_CONFIG_SCHEMA, getTriggerDefinition, getTriggerName, getTriggerPresentation, isTriggerVisible, triggerCatalog, triggerDefinitions, type DashboardRunConfig, type DashboardRunEndpointOptions, type DashboardRunField, type HttpTriggerEndpointOptions, type HttpTriggerScope, type TriggerType, } from "./triggers/index.js";
3
+ export { getDashboardRunEndpoint, getDashboardRunEndpointKey, getHttpTriggerEndpoint, getHttpTriggerEndpointKey, getMailhookAddress, getMailhookAddressKey, DASHBOARD_RUN_CONFIG_SCHEMA, getTriggerDefinition, getTriggerName, getTriggerPresentation, isTriggerVisible, PLATFORM_EMAIL_DOMAIN, triggerCatalog, triggerDefinitions, type DashboardRunConfig, type DashboardRunEndpointOptions, type DashboardRunField, type HttpTriggerEndpointOptions, type HttpTriggerScope, type MailhookAddressOptions, type MailhookScope, type TriggerType, } from "./triggers/index.js";
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  export { airtableService, anthropicService, apolloService, asanaService, brevoService, cerebrasService, cloudflareService, cohereService, deepinfraService, deepseekService, firecrawlService, fireworksService, getIntegrationService, githubService, googleGenaiService, googleService, groqService, huggingfaceService, integrationCatalog, linearService, microsoftService, millionverifierService, mistralService, openaiService, openrouterService, perplexityService, postgresService, resendService, scrapflyService, slackService, tidycalService, togetheraiService, trelloService, vercelAiGatewayService, vercelService, whatsappService, xaiService, } from "./catalog.js";
2
2
  export { defineIntegrationCatalog, defineIntegrationService, integrationScope, } from "./types.js";
3
- export { getDashboardRunEndpoint, getDashboardRunEndpointKey, getHttpTriggerEndpoint, getHttpTriggerEndpointKey, DASHBOARD_RUN_CONFIG_SCHEMA, getTriggerDefinition, getTriggerName, getTriggerPresentation, isTriggerVisible, triggerCatalog, triggerDefinitions, } from "./triggers/index.js";
3
+ export { getDashboardRunEndpoint, getDashboardRunEndpointKey, getHttpTriggerEndpoint, getHttpTriggerEndpointKey, getMailhookAddress, getMailhookAddressKey, DASHBOARD_RUN_CONFIG_SCHEMA, getTriggerDefinition, getTriggerName, getTriggerPresentation, isTriggerVisible, PLATFORM_EMAIL_DOMAIN, triggerCatalog, triggerDefinitions, } from "./triggers/index.js";
@@ -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.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniDiscriminatedUnion<[z.ZodMiniObject<{
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
- required: z.ZodMiniPrefault<z.ZodMiniBoolean<boolean>>;
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
- type: z.ZodMiniLiteral<"select">;
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
- type: z.ZodMiniLiteral<"checkbox">;
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
- }, z.core.$strip>], "type">>;
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>;
@@ -70,6 +123,15 @@ export declare const coreTriggerDefinitions: {
70
123
  readonly name: "HTTP request";
71
124
  readonly type: "http.request";
72
125
  };
126
+ readonly mailhookEmailReceived: {
127
+ readonly getPrimary: ({ automationId, config, hookSlot, projectId, scopePath }: import("..").TriggerPresentationContext) => {
128
+ copyable: true;
129
+ value: string;
130
+ };
131
+ readonly icon: "webhook";
132
+ readonly name: "Mailhook";
133
+ readonly type: "mailhook.email.received";
134
+ };
73
135
  readonly dashboardRun: {
74
136
  readonly getDetails: ({ config }: import("..").TriggerPresentationContext) => {
75
137
  label: string;
@@ -85,15 +147,19 @@ interface DashboardRunFieldBase {
85
147
  description?: string;
86
148
  /** Visible field label. */
87
149
  label: string;
150
+ /** Property name used in submitted trigger data. */
151
+ name: string;
88
152
  /** Whether the form must contain a value. Defaults to true. */
89
153
  required?: boolean;
90
154
  }
91
155
  export type DashboardRunField = (DashboardRunFieldBase & {
156
+ defaultValue?: string;
92
157
  maxLength?: number;
93
158
  minLength?: number;
94
159
  placeholder?: string;
95
- type: "email" | "text" | "textarea" | "url";
160
+ type: "email" | "phone" | "text" | "textarea" | "url";
96
161
  }) | (DashboardRunFieldBase & {
162
+ defaultValue?: number;
97
163
  max?: number;
98
164
  min?: number;
99
165
  placeholder?: string;
@@ -101,6 +167,23 @@ export type DashboardRunField = (DashboardRunFieldBase & {
101
167
  step?: number;
102
168
  type: "number";
103
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;
104
187
  options: readonly {
105
188
  label: string;
106
189
  value: string;
@@ -108,13 +191,32 @@ export type DashboardRunField = (DashboardRunFieldBase & {
108
191
  placeholder?: string;
109
192
  type: "select";
110
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;
111
213
  type: "checkbox";
112
214
  });
113
- export interface DashboardRunConfig<TFields extends Record<string, DashboardRunField> = Record<string, DashboardRunField>> {
215
+ export interface DashboardRunConfig<TFields extends readonly DashboardRunField[] = readonly DashboardRunField[]> {
114
216
  /** Supporting text shown below the form title. */
115
217
  description?: string;
116
- /** Named fields rendered in declaration order. */
117
- fields: TFields;
218
+ /** Ordered fields. Omit to run immediately. */
219
+ fields?: TFields;
118
220
  /** Submit button text. Defaults to "Run". */
119
221
  submitLabel?: string;
120
222
  /** Form heading. */
@@ -127,6 +229,8 @@ export interface DashboardRunEndpointOptions {
127
229
  scopePath?: readonly number[];
128
230
  }
129
231
  export type HttpTriggerScope = "trigger" | "automation" | "project";
232
+ export type MailhookScope = HttpTriggerScope;
233
+ export declare const PLATFORM_EMAIL_DOMAIN = "automations.automate.ax";
130
234
  export interface HttpTriggerEndpointOptions {
131
235
  appOrigin: string;
132
236
  automationId: string;
@@ -135,6 +239,14 @@ export interface HttpTriggerEndpointOptions {
135
239
  scope: HttpTriggerScope;
136
240
  scopePath?: readonly number[];
137
241
  }
242
+ export interface MailhookAddressOptions {
243
+ automationId: string;
244
+ hookSlot: number;
245
+ plusPath?: string;
246
+ projectId: string;
247
+ scope: MailhookScope;
248
+ scopePath?: readonly number[];
249
+ }
138
250
  /**
139
251
  * Returns the public URL for one deployed HTTP trigger.
140
252
  *
@@ -147,6 +259,21 @@ export declare function getHttpTriggerEndpoint(options: HttpTriggerEndpointOptio
147
259
  * @param options - Trigger and owning resource identity.
148
260
  */
149
261
  export declare function getHttpTriggerEndpointKey(options: Omit<HttpTriggerEndpointOptions, "appOrigin">): string;
262
+ /**
263
+ * Returns the unique inbound address for one deployed mailhook.
264
+ *
265
+ * Add `+suffix` before the `@` to carry a routing value into the event.
266
+ *
267
+ * @param options - Mailhook identity and sharing scope.
268
+ * @throws When the generated local part exceeds the email size limit.
269
+ */
270
+ export declare function getMailhookAddress(options: MailhookAddressOptions): string;
271
+ /**
272
+ * Returns the local-part router key for one configured mailhook scope.
273
+ *
274
+ * @param options - Mailhook identity and sharing scope.
275
+ */
276
+ export declare function getMailhookAddressKey(options: MailhookAddressOptions): string;
150
277
  /**
151
278
  * Returns the organization-authenticated submission endpoint for one dashboard
152
279
  * run.
@@ -1,4 +1,7 @@
1
1
  import * as z from "zod/mini";
2
+ const MAX_EMAIL_LOCAL_PART_BYTES = 64;
3
+ const EMAIL_SCHEMA = z.email();
4
+ const URL_SCHEMA = z.url();
2
5
  const CRON_PRESENTATION_CONFIG_SCHEMA = z.object({
3
6
  schedule: z.string(),
4
7
  timeZone: z.prefault(z.string(), "UTC"),
@@ -6,6 +9,9 @@ const CRON_PRESENTATION_CONFIG_SCHEMA = z.object({
6
9
  const HTTP_PRESENTATION_CONFIG_SCHEMA = z.object({
7
10
  scope: z.prefault(z.enum(["trigger", "automation", "project"]), "trigger"),
8
11
  });
12
+ const MAILHOOK_PRESENTATION_CONFIG_SCHEMA = z.object({
13
+ scope: z.prefault(z.enum(["trigger", "automation", "project"]), "trigger"),
14
+ });
9
15
  const INVOCATION_PRESENTATION_CONFIG_SCHEMA = z.object({
10
16
  entrypoint: z.string(),
11
17
  });
@@ -20,25 +26,48 @@ const FIELD_LENGTH_SCHEMA = z.int().check(z.nonnegative());
20
26
  const DASHBOARD_RUN_FIELD_BASE_SCHEMA = {
21
27
  description: z.optional(FIELD_DESCRIPTION_SCHEMA),
22
28
  label: FIELD_LABEL_SCHEMA,
23
- required: z.prefault(z.boolean(), true),
29
+ name: FIELD_NAME_SCHEMA,
24
30
  };
25
31
  const DASHBOARD_RUN_TEXT_FIELD_SCHEMA = z.object({
26
32
  ...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
33
+ defaultValue: z.optional(z.string()),
27
34
  maxLength: z.optional(FIELD_LENGTH_SCHEMA),
28
35
  minLength: z.optional(FIELD_LENGTH_SCHEMA),
29
36
  placeholder: z.optional(z.string()),
30
- type: z.enum(["email", "text", "textarea", "url"]),
37
+ required: z.prefault(z.boolean(), true),
38
+ type: z.enum(["email", "phone", "text", "textarea", "url"]),
31
39
  });
32
40
  const DASHBOARD_RUN_NUMBER_FIELD_SCHEMA = z.object({
33
41
  ...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
42
+ defaultValue: z.optional(z.number()),
34
43
  max: z.optional(z.number()),
35
44
  min: z.optional(z.number()),
36
45
  placeholder: z.optional(z.string()),
46
+ required: z.prefault(z.boolean(), true),
37
47
  step: z.prefault(z.number().check(z.positive()), 1),
38
48
  type: z.literal("number"),
39
49
  });
40
- const DASHBOARD_RUN_SELECT_FIELD_SCHEMA = z.object({
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 = {
41
69
  ...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
70
+ defaultValue: z.optional(FIELD_NAME_SCHEMA),
42
71
  options: z
43
72
  .array(z.object({
44
73
  label: FIELD_LABEL_SCHEMA,
@@ -46,20 +75,49 @@ const DASHBOARD_RUN_SELECT_FIELD_SCHEMA = z.object({
46
75
  }))
47
76
  .check(z.minLength(1)),
48
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,
49
82
  type: z.literal("select"),
50
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
+ });
51
101
  const DASHBOARD_RUN_CHECKBOX_FIELD_SCHEMA = z.object({
52
102
  ...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
103
+ defaultValue: z.prefault(z.boolean(), false),
104
+ required: z.prefault(z.boolean(), false),
53
105
  type: z.literal("checkbox"),
54
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."));
55
118
  export const DASHBOARD_RUN_CONFIG_SCHEMA = z.object({
56
119
  description: z.optional(FIELD_DESCRIPTION_SCHEMA),
57
- fields: z.record(FIELD_NAME_SCHEMA, z.discriminatedUnion("type", [
58
- DASHBOARD_RUN_TEXT_FIELD_SCHEMA,
59
- DASHBOARD_RUN_NUMBER_FIELD_SCHEMA,
60
- DASHBOARD_RUN_SELECT_FIELD_SCHEMA,
61
- DASHBOARD_RUN_CHECKBOX_FIELD_SCHEMA,
62
- ])),
120
+ fields: z.prefault(DASHBOARD_RUN_FIELDS_SCHEMA, []),
63
121
  submitLabel: z.prefault(z.string().check(z.trim(), z.minLength(1), z.maxLength(100)), "Run"),
64
122
  title: z.string().check(z.trim(), z.minLength(1), z.maxLength(255)),
65
123
  });
@@ -103,6 +161,21 @@ export const coreTriggerDefinitions = {
103
161
  name: "HTTP request",
104
162
  type: "http.request",
105
163
  },
164
+ mailhookEmailReceived: {
165
+ getPrimary: ({ automationId, config, hookSlot, projectId, scopePath }) => ({
166
+ copyable: true,
167
+ value: getMailhookAddress({
168
+ automationId,
169
+ hookSlot,
170
+ projectId,
171
+ scope: MAILHOOK_PRESENTATION_CONFIG_SCHEMA.parse(config).scope,
172
+ scopePath,
173
+ }),
174
+ }),
175
+ icon: "webhook",
176
+ name: "Mailhook",
177
+ type: "mailhook.email.received",
178
+ },
106
179
  dashboardRun: {
107
180
  getDetails: ({ config }) => [
108
181
  {
@@ -115,6 +188,7 @@ export const coreTriggerDefinitions = {
115
188
  type: "dashboard.run",
116
189
  },
117
190
  };
191
+ export const PLATFORM_EMAIL_DOMAIN = "automations.automate.ax";
118
192
  /**
119
193
  * Returns the public URL for one deployed HTTP trigger.
120
194
  *
@@ -138,6 +212,39 @@ export function getHttpTriggerEndpointKey(options) {
138
212
  options.hookSlot,
139
213
  ].join(".")}`;
140
214
  }
215
+ /**
216
+ * Returns the unique inbound address for one deployed mailhook.
217
+ *
218
+ * Add `+suffix` before the `@` to carry a routing value into the event.
219
+ *
220
+ * @param options - Mailhook identity and sharing scope.
221
+ * @throws When the generated local part exceeds the email size limit.
222
+ */
223
+ export function getMailhookAddress(options) {
224
+ const localPart = `${getMailhookAddressKey(options)}${options.plusPath ? `+${options.plusPath}` : ""}`;
225
+ if (new TextEncoder().encode(localPart).length > MAX_EMAIL_LOCAL_PART_BYTES) {
226
+ throw new RangeError("Mailhook address local part exceeds 64 bytes.");
227
+ }
228
+ return EMAIL_SCHEMA.parse(`${localPart}@${PLATFORM_EMAIL_DOMAIN}`);
229
+ }
230
+ /**
231
+ * Returns the local-part router key for one configured mailhook scope.
232
+ *
233
+ * @param options - Mailhook identity and sharing scope.
234
+ */
235
+ export function getMailhookAddressKey(options) {
236
+ if (options.scope === "project")
237
+ return `p${typeIdSuffix(options.projectId)}`;
238
+ if (options.scope === "automation") {
239
+ return `a${typeIdSuffix(options.automationId)}`;
240
+ }
241
+ return `a${typeIdSuffix(options.automationId)}.${[
242
+ ...(options.scopePath ?? []),
243
+ options.hookSlot,
244
+ ]
245
+ .map((segment) => segment.toString(36))
246
+ .join(".")}`;
247
+ }
141
248
  /**
142
249
  * Returns the organization-authenticated submission endpoint for one dashboard
143
250
  * run.
@@ -158,3 +265,68 @@ export function getDashboardRunEndpointKey(options) {
158
265
  options.hookSlot,
159
266
  ].join(".")}`;
160
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
+ }
325
+ /**
326
+ * Removes the redundant TypeID prefix from an address router.
327
+ *
328
+ * @param id - Project or automation TypeID.
329
+ */
330
+ function typeIdSuffix(id) {
331
+ return id.includes("_") ? id.slice(id.indexOf("_") + 1) : id;
332
+ }
@@ -1,5 +1,5 @@
1
1
  import type { TriggerDefinition, TriggerPresentation, TriggerPresentationContext, TriggerScopePresentation } from "../types.js";
2
- export { getDashboardRunEndpoint, getDashboardRunEndpointKey, getHttpTriggerEndpoint, getHttpTriggerEndpointKey, DASHBOARD_RUN_CONFIG_SCHEMA, type DashboardRunConfig, type DashboardRunEndpointOptions, type DashboardRunField, type HttpTriggerEndpointOptions, type HttpTriggerScope, } from "./core.js";
2
+ export { getDashboardRunEndpoint, getDashboardRunEndpointKey, getHttpTriggerEndpoint, getHttpTriggerEndpointKey, getMailhookAddress, getMailhookAddressKey, PLATFORM_EMAIL_DOMAIN, DASHBOARD_RUN_CONFIG_SCHEMA, type DashboardRunConfig, type DashboardRunEndpointOptions, type DashboardRunField, type HttpTriggerEndpointOptions, type HttpTriggerScope, type MailhookAddressOptions, type MailhookScope, } from "./core.js";
3
3
  /** Plain shared definitions for every public trigger type. */
4
4
  export declare const triggerDefinitions: {
5
5
  readonly whatsappMessageDelivered: {
@@ -1075,6 +1075,15 @@ export declare const triggerDefinitions: {
1075
1075
  readonly name: "HTTP request";
1076
1076
  readonly type: "http.request";
1077
1077
  };
1078
+ readonly mailhookEmailReceived: {
1079
+ readonly getPrimary: ({ automationId, config, hookSlot, projectId, scopePath }: TriggerPresentationContext) => {
1080
+ copyable: true;
1081
+ value: string;
1082
+ };
1083
+ readonly icon: "webhook";
1084
+ readonly name: "Mailhook";
1085
+ readonly type: "mailhook.email.received";
1086
+ };
1078
1087
  readonly dashboardRun: {
1079
1088
  readonly getDetails: ({ config }: TriggerPresentationContext) => {
1080
1089
  label: string;
@@ -1564,6 +1573,14 @@ export declare const triggerCatalog: ({
1564
1573
  };
1565
1574
  icon: "webhook";
1566
1575
  type: "http.request";
1576
+ } | {
1577
+ name: string;
1578
+ getPrimary: ({ automationId, config, hookSlot, projectId, scopePath }: TriggerPresentationContext) => {
1579
+ copyable: true;
1580
+ value: string;
1581
+ };
1582
+ icon: "webhook";
1583
+ type: "mailhook.email.received";
1567
1584
  } | {
1568
1585
  name: string;
1569
1586
  getDetails: ({ config }: TriggerPresentationContext) => {
@@ -12,7 +12,7 @@ import { trelloTriggerDefinitions } from "./trello.js";
12
12
  import { vercelTriggerDefinitions } from "./vercel.js";
13
13
  import { whatsappTriggerDefinitions } from "./whatsapp.js";
14
14
  import { getIntegrationService } from "../catalog.js";
15
- export { getDashboardRunEndpoint, getDashboardRunEndpointKey, getHttpTriggerEndpoint, getHttpTriggerEndpointKey, DASHBOARD_RUN_CONFIG_SCHEMA, } from "./core.js";
15
+ export { getDashboardRunEndpoint, getDashboardRunEndpointKey, getHttpTriggerEndpoint, getHttpTriggerEndpointKey, getMailhookAddress, getMailhookAddressKey, PLATFORM_EMAIL_DOMAIN, DASHBOARD_RUN_CONFIG_SCHEMA, } from "./core.js";
16
16
  /** Plain shared definitions for every public trigger type. */
17
17
  export const triggerDefinitions = {
18
18
  ...airtableTriggerDefinitions,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automate.ax/catalog",
3
- "version": "0.63.0",
3
+ "version": "0.65.0",
4
4
  "description": "Shared integration service and trigger definitions for Automate.ax.",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/index.ts CHANGED
@@ -61,11 +61,14 @@ export {
61
61
  getDashboardRunEndpointKey,
62
62
  getHttpTriggerEndpoint,
63
63
  getHttpTriggerEndpointKey,
64
+ getMailhookAddress,
65
+ getMailhookAddressKey,
64
66
  DASHBOARD_RUN_CONFIG_SCHEMA,
65
67
  getTriggerDefinition,
66
68
  getTriggerName,
67
69
  getTriggerPresentation,
68
70
  isTriggerVisible,
71
+ PLATFORM_EMAIL_DOMAIN,
69
72
  triggerCatalog,
70
73
  triggerDefinitions,
71
74
  type DashboardRunConfig,
@@ -73,5 +76,7 @@ export {
73
76
  type DashboardRunField,
74
77
  type HttpTriggerEndpointOptions,
75
78
  type HttpTriggerScope,
79
+ type MailhookAddressOptions,
80
+ type MailhookScope,
76
81
  type TriggerType,
77
82
  } from "./triggers"
@@ -1,6 +1,9 @@
1
1
  import type { TriggerDefinition } from "../types"
2
2
  import * as z from "zod/mini"
3
3
 
4
+ const MAX_EMAIL_LOCAL_PART_BYTES = 64
5
+ const EMAIL_SCHEMA = z.email()
6
+ const URL_SCHEMA = z.url()
4
7
  const CRON_PRESENTATION_CONFIG_SCHEMA = z.object({
5
8
  schedule: z.string(),
6
9
  timeZone: z.prefault(z.string(), "UTC"),
@@ -8,6 +11,9 @@ const CRON_PRESENTATION_CONFIG_SCHEMA = z.object({
8
11
  const HTTP_PRESENTATION_CONFIG_SCHEMA = z.object({
9
12
  scope: z.prefault(z.enum(["trigger", "automation", "project"]), "trigger"),
10
13
  })
14
+ const MAILHOOK_PRESENTATION_CONFIG_SCHEMA = z.object({
15
+ scope: z.prefault(z.enum(["trigger", "automation", "project"]), "trigger"),
16
+ })
11
17
  const INVOCATION_PRESENTATION_CONFIG_SCHEMA = z.object({
12
18
  entrypoint: z.string(),
13
19
  })
@@ -22,25 +28,48 @@ const FIELD_LENGTH_SCHEMA = z.int().check(z.nonnegative())
22
28
  const DASHBOARD_RUN_FIELD_BASE_SCHEMA = {
23
29
  description: z.optional(FIELD_DESCRIPTION_SCHEMA),
24
30
  label: FIELD_LABEL_SCHEMA,
25
- required: z.prefault(z.boolean(), true),
31
+ name: FIELD_NAME_SCHEMA,
26
32
  }
27
33
  const DASHBOARD_RUN_TEXT_FIELD_SCHEMA = z.object({
28
34
  ...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
35
+ defaultValue: z.optional(z.string()),
29
36
  maxLength: z.optional(FIELD_LENGTH_SCHEMA),
30
37
  minLength: z.optional(FIELD_LENGTH_SCHEMA),
31
38
  placeholder: z.optional(z.string()),
32
- type: z.enum(["email", "text", "textarea", "url"]),
39
+ required: z.prefault(z.boolean(), true),
40
+ type: z.enum(["email", "phone", "text", "textarea", "url"]),
33
41
  })
34
42
  const DASHBOARD_RUN_NUMBER_FIELD_SCHEMA = z.object({
35
43
  ...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
44
+ defaultValue: z.optional(z.number()),
36
45
  max: z.optional(z.number()),
37
46
  min: z.optional(z.number()),
38
47
  placeholder: z.optional(z.string()),
48
+ required: z.prefault(z.boolean(), true),
39
49
  step: z.prefault(z.number().check(z.positive()), 1),
40
50
  type: z.literal("number"),
41
51
  })
42
- const DASHBOARD_RUN_SELECT_FIELD_SCHEMA = z.object({
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({
43
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 = {
71
+ ...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
72
+ defaultValue: z.optional(FIELD_NAME_SCHEMA),
44
73
  options: z
45
74
  .array(
46
75
  z.object({
@@ -50,24 +79,62 @@ const DASHBOARD_RUN_SELECT_FIELD_SCHEMA = z.object({
50
79
  )
51
80
  .check(z.minLength(1)),
52
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,
53
86
  type: z.literal("select"),
54
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
+ })
55
107
  const DASHBOARD_RUN_CHECKBOX_FIELD_SCHEMA = z.object({
56
108
  ...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
109
+ defaultValue: z.prefault(z.boolean(), false),
110
+ required: z.prefault(z.boolean(), false),
57
111
  type: z.literal("checkbox"),
58
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
+ )
59
134
 
60
135
  export const DASHBOARD_RUN_CONFIG_SCHEMA = z.object({
61
136
  description: z.optional(FIELD_DESCRIPTION_SCHEMA),
62
- fields: z.record(
63
- FIELD_NAME_SCHEMA,
64
- z.discriminatedUnion("type", [
65
- DASHBOARD_RUN_TEXT_FIELD_SCHEMA,
66
- DASHBOARD_RUN_NUMBER_FIELD_SCHEMA,
67
- DASHBOARD_RUN_SELECT_FIELD_SCHEMA,
68
- DASHBOARD_RUN_CHECKBOX_FIELD_SCHEMA,
69
- ]),
70
- ),
137
+ fields: z.prefault(DASHBOARD_RUN_FIELDS_SCHEMA, []),
71
138
  submitLabel: z.prefault(
72
139
  z.string().check(z.trim(), z.minLength(1), z.maxLength(100)),
73
140
  "Run",
@@ -123,6 +190,21 @@ export const coreTriggerDefinitions = {
123
190
  name: "HTTP request",
124
191
  type: "http.request",
125
192
  },
193
+ mailhookEmailReceived: {
194
+ getPrimary: ({ automationId, config, hookSlot, projectId, scopePath }) => ({
195
+ copyable: true,
196
+ value: getMailhookAddress({
197
+ automationId,
198
+ hookSlot,
199
+ projectId,
200
+ scope: MAILHOOK_PRESENTATION_CONFIG_SCHEMA.parse(config).scope,
201
+ scopePath,
202
+ }),
203
+ }),
204
+ icon: "webhook",
205
+ name: "Mailhook",
206
+ type: "mailhook.email.received",
207
+ },
126
208
  dashboardRun: {
127
209
  getDetails: ({ config }) => [
128
210
  {
@@ -143,18 +225,23 @@ interface DashboardRunFieldBase {
143
225
  /** Visible field label. */
144
226
  label: string
145
227
 
228
+ /** Property name used in submitted trigger data. */
229
+ name: string
230
+
146
231
  /** Whether the form must contain a value. Defaults to true. */
147
232
  required?: boolean
148
233
  }
149
234
 
150
235
  export type DashboardRunField =
151
236
  | (DashboardRunFieldBase & {
237
+ defaultValue?: string
152
238
  maxLength?: number
153
239
  minLength?: number
154
240
  placeholder?: string
155
- type: "email" | "text" | "textarea" | "url"
241
+ type: "email" | "phone" | "text" | "textarea" | "url"
156
242
  })
157
243
  | (DashboardRunFieldBase & {
244
+ defaultValue?: number
158
245
  max?: number
159
246
  min?: number
160
247
  placeholder?: string
@@ -164,25 +251,59 @@ export type DashboardRunField =
164
251
  type: "number"
165
252
  })
166
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
167
275
  options: readonly { label: string; value: string }[]
168
276
  placeholder?: string
169
277
  type: "select"
170
278
  })
171
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
172
296
  type: "checkbox"
173
297
  })
174
298
 
175
299
  export interface DashboardRunConfig<
176
- TFields extends Record<string, DashboardRunField> = Record<
177
- string,
178
- DashboardRunField
179
- >,
300
+ TFields extends readonly DashboardRunField[] = readonly DashboardRunField[],
180
301
  > {
181
302
  /** Supporting text shown below the form title. */
182
303
  description?: string
183
304
 
184
- /** Named fields rendered in declaration order. */
185
- fields: TFields
305
+ /** Ordered fields. Omit to run immediately. */
306
+ fields?: TFields
186
307
 
187
308
  /** Submit button text. Defaults to "Run". */
188
309
  submitLabel?: string
@@ -199,6 +320,9 @@ export interface DashboardRunEndpointOptions {
199
320
  }
200
321
 
201
322
  export type HttpTriggerScope = "trigger" | "automation" | "project"
323
+ export type MailhookScope = HttpTriggerScope
324
+
325
+ export const PLATFORM_EMAIL_DOMAIN = "automations.automate.ax"
202
326
 
203
327
  export interface HttpTriggerEndpointOptions {
204
328
  appOrigin: string
@@ -209,6 +333,15 @@ export interface HttpTriggerEndpointOptions {
209
333
  scopePath?: readonly number[]
210
334
  }
211
335
 
336
+ export interface MailhookAddressOptions {
337
+ automationId: string
338
+ hookSlot: number
339
+ plusPath?: string
340
+ projectId: string
341
+ scope: MailhookScope
342
+ scopePath?: readonly number[]
343
+ }
344
+
212
345
  /**
213
346
  * Returns the public URL for one deployed HTTP trigger.
214
347
  *
@@ -237,6 +370,42 @@ export function getHttpTriggerEndpointKey(
237
370
  ].join(".")}`
238
371
  }
239
372
 
373
+ /**
374
+ * Returns the unique inbound address for one deployed mailhook.
375
+ *
376
+ * Add `+suffix` before the `@` to carry a routing value into the event.
377
+ *
378
+ * @param options - Mailhook identity and sharing scope.
379
+ * @throws When the generated local part exceeds the email size limit.
380
+ */
381
+ export function getMailhookAddress(options: MailhookAddressOptions) {
382
+ const localPart = `${getMailhookAddressKey(options)}${options.plusPath ? `+${options.plusPath}` : ""}`
383
+ if (new TextEncoder().encode(localPart).length > MAX_EMAIL_LOCAL_PART_BYTES) {
384
+ throw new RangeError("Mailhook address local part exceeds 64 bytes.")
385
+ }
386
+
387
+ return EMAIL_SCHEMA.parse(`${localPart}@${PLATFORM_EMAIL_DOMAIN}`)
388
+ }
389
+
390
+ /**
391
+ * Returns the local-part router key for one configured mailhook scope.
392
+ *
393
+ * @param options - Mailhook identity and sharing scope.
394
+ */
395
+ export function getMailhookAddressKey(options: MailhookAddressOptions) {
396
+ if (options.scope === "project") return `p${typeIdSuffix(options.projectId)}`
397
+ if (options.scope === "automation") {
398
+ return `a${typeIdSuffix(options.automationId)}`
399
+ }
400
+
401
+ return `a${typeIdSuffix(options.automationId)}.${[
402
+ ...(options.scopePath ?? []),
403
+ options.hookSlot,
404
+ ]
405
+ .map((segment) => segment.toString(36))
406
+ .join(".")}`
407
+ }
408
+
240
409
  /**
241
410
  * Returns the organization-authenticated submission endpoint for one dashboard
242
411
  * run.
@@ -263,3 +432,95 @@ export function getDashboardRunEndpointKey(
263
432
  options.hookSlot,
264
433
  ].join(".")}`
265
434
  }
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
+
519
+ /**
520
+ * Removes the redundant TypeID prefix from an address router.
521
+ *
522
+ * @param id - Project or automation TypeID.
523
+ */
524
+ function typeIdSuffix(id: string) {
525
+ return id.includes("_") ? id.slice(id.indexOf("_") + 1) : id
526
+ }
@@ -24,12 +24,17 @@ export {
24
24
  getDashboardRunEndpointKey,
25
25
  getHttpTriggerEndpoint,
26
26
  getHttpTriggerEndpointKey,
27
+ getMailhookAddress,
28
+ getMailhookAddressKey,
29
+ PLATFORM_EMAIL_DOMAIN,
27
30
  DASHBOARD_RUN_CONFIG_SCHEMA,
28
31
  type DashboardRunConfig,
29
32
  type DashboardRunEndpointOptions,
30
33
  type DashboardRunField,
31
34
  type HttpTriggerEndpointOptions,
32
35
  type HttpTriggerScope,
36
+ type MailhookAddressOptions,
37
+ type MailhookScope,
33
38
  } from "./core"
34
39
 
35
40
  /** Plain shared definitions for every public trigger type. */