@automate.ax/catalog 0.75.0 → 0.77.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.
Files changed (63) hide show
  1. package/dist/authoring.d.ts +1 -0
  2. package/dist/authoring.js +1 -0
  3. package/dist/catalog.d.ts +142 -74
  4. package/dist/catalog.js +74 -13
  5. package/dist/index.d.ts +1 -1
  6. package/dist/index.js +1 -1
  7. package/dist/triggers/airtable.js +1 -2
  8. package/dist/triggers/asana.js +1 -2
  9. package/dist/triggers/brevo.js +1 -2
  10. package/dist/triggers/core-dashboard.d.ts +374 -0
  11. package/dist/triggers/core-dashboard.js +202 -0
  12. package/dist/triggers/core-http.d.ts +30 -0
  13. package/dist/triggers/core-http.js +43 -0
  14. package/dist/triggers/core-invocation.d.ts +9 -0
  15. package/dist/triggers/core-invocation.js +15 -0
  16. package/dist/triggers/core-mailhook.d.ts +35 -0
  17. package/dist/triggers/core-mailhook.js +63 -0
  18. package/dist/triggers/core-schedule.d.ts +9 -0
  19. package/dist/triggers/core-schedule.js +17 -0
  20. package/dist/triggers/core.d.ts +15 -426
  21. package/dist/triggers/core.js +16 -346
  22. package/dist/triggers/github.js +4 -5
  23. package/dist/triggers/google.d.ts +143 -0
  24. package/dist/triggers/google.js +92 -5
  25. package/dist/triggers/index.d.ts +347 -74
  26. package/dist/triggers/index.js +2 -1
  27. package/dist/triggers/linear.js +1 -2
  28. package/dist/triggers/microsoft.js +3 -4
  29. package/dist/triggers/name.d.ts +13 -0
  30. package/dist/triggers/name.js +31 -0
  31. package/dist/triggers/resend.js +1 -2
  32. package/dist/triggers/slack.js +3 -4
  33. package/dist/triggers/trello.js +1 -2
  34. package/dist/triggers/vercel.d.ts +27 -27
  35. package/dist/triggers/vercel.js +10 -11
  36. package/dist/triggers/whatsapp.js +1 -2
  37. package/dist/types.d.ts +1 -1
  38. package/dist/types.js +3 -3
  39. package/package.json +118 -5
  40. package/src/authoring.ts +8 -0
  41. package/src/catalog.ts +76 -13
  42. package/src/index.ts +2 -0
  43. package/src/triggers/airtable.ts +1 -2
  44. package/src/triggers/asana.ts +1 -2
  45. package/src/triggers/brevo.ts +1 -2
  46. package/src/triggers/core-dashboard.ts +361 -0
  47. package/src/triggers/core-http.ts +69 -0
  48. package/src/triggers/core-invocation.ts +18 -0
  49. package/src/triggers/core-mailhook.ts +83 -0
  50. package/src/triggers/core-schedule.ts +21 -0
  51. package/src/triggers/core.ts +38 -544
  52. package/src/triggers/github.ts +4 -5
  53. package/src/triggers/google.ts +93 -5
  54. package/src/triggers/index.ts +2 -1
  55. package/src/triggers/linear.ts +1 -2
  56. package/src/triggers/microsoft.ts +3 -4
  57. package/src/triggers/name.ts +37 -0
  58. package/src/triggers/resend.ts +1 -2
  59. package/src/triggers/slack.ts +3 -4
  60. package/src/triggers/trello.ts +1 -2
  61. package/src/triggers/vercel.ts +10 -11
  62. package/src/triggers/whatsapp.ts +1 -2
  63. package/src/types.ts +4 -4
package/src/catalog.ts CHANGED
@@ -9,7 +9,7 @@ const API_KEY_FIELD = {
9
9
  } as const
10
10
 
11
11
  export const airtableService = defineIntegrationService({
12
- connectionMethods: [{ id: "default", name: "OAuth", type: "redirect" }],
12
+ connectionMethods: [{ id: "oauth", name: "OAuth", type: "redirect" }],
13
13
  description: "Connect an Airtable account.",
14
14
  id: "airtable",
15
15
  name: "Airtable",
@@ -39,7 +39,7 @@ export const apolloService = defineIntegrationService({
39
39
  })
40
40
 
41
41
  export const asanaService = defineIntegrationService({
42
- connectionMethods: [{ id: "default", name: "OAuth", type: "redirect" }],
42
+ connectionMethods: [{ id: "oauth", name: "OAuth", type: "redirect" }],
43
43
  description: "Connect an Asana account.",
44
44
  id: "asana",
45
45
  name: "Asana",
@@ -82,6 +82,52 @@ export const cloudflareService = defineIntegrationService({
82
82
  preferredConnectionMethodId: "oauth",
83
83
  })
84
84
 
85
+ export const chatgptService = defineIntegrationService({
86
+ connectionMethods: [
87
+ {
88
+ fields: [
89
+ {
90
+ input: "password",
91
+ label: "Workspace Agent access token",
92
+ name: "apiKey",
93
+ placeholder: "Paste your ChatGPT access token",
94
+ required: true,
95
+ },
96
+ ],
97
+ id: "access-token",
98
+ name: "Access token",
99
+ type: "form",
100
+ },
101
+ ],
102
+ description: "Connect a Workspace Agent access token.",
103
+ icon: "openai",
104
+ id: "chatgpt",
105
+ name: "ChatGPT",
106
+ })
107
+
108
+ export const codexService = defineIntegrationService({
109
+ connectionMethods: [
110
+ {
111
+ fields: [
112
+ {
113
+ input: "password",
114
+ label: "Codex access token",
115
+ name: "apiKey",
116
+ placeholder: "Paste your Codex access token",
117
+ required: true,
118
+ },
119
+ ],
120
+ id: "access-token",
121
+ name: "Access token",
122
+ type: "form",
123
+ },
124
+ ],
125
+ description: "Connect a Codex workspace access token.",
126
+ icon: "openai",
127
+ id: "codex",
128
+ name: "Codex",
129
+ })
130
+
85
131
  export const cohereService = defineApiKeyService({
86
132
  description: "Connect a Cohere API key.",
87
133
  id: "cohere",
@@ -114,14 +160,16 @@ export const fireworksService = defineApiKeyService({
114
160
  })
115
161
 
116
162
  export const githubService = defineIntegrationService({
117
- connectionMethods: [{ id: "default", name: "GitHub App", type: "redirect" }],
163
+ connectionMethods: [
164
+ { id: "github-app", name: "GitHub App", type: "redirect" },
165
+ ],
118
166
  description: "Install Automate.ax on a GitHub account or organization.",
119
167
  id: "github",
120
168
  name: "GitHub",
121
169
  })
122
170
 
123
171
  export const googleService = defineIntegrationService({
124
- connectionMethods: [{ id: "default", name: "OAuth", type: "redirect" }],
172
+ connectionMethods: [{ id: "oauth", name: "OAuth", type: "redirect" }],
125
173
  connectionNotice: {
126
174
  action: {
127
175
  href: "mailto:hello@automate.ax?subject=Google%20integration%20access",
@@ -149,22 +197,35 @@ export const groqService = defineApiKeyService({
149
197
  name: "Groq",
150
198
  })
151
199
 
152
- export const huggingfaceService = defineApiKeyService({
200
+ export const huggingfaceService = defineIntegrationService({
201
+ connectionMethods: [
202
+ {
203
+ fields: [
204
+ {
205
+ ...API_KEY_FIELD,
206
+ label: "Access token",
207
+ placeholder: "hf_...",
208
+ },
209
+ ],
210
+ id: "access-token",
211
+ name: "Access token",
212
+ type: "form",
213
+ },
214
+ ],
153
215
  description: "Connect a Hugging Face access token.",
154
216
  id: "huggingface",
155
217
  name: "Hugging Face",
156
- placeholder: "hf_...",
157
218
  })
158
219
 
159
220
  export const linearService = defineIntegrationService({
160
- connectionMethods: [{ id: "default", name: "OAuth", type: "redirect" }],
221
+ connectionMethods: [{ id: "oauth", name: "OAuth", type: "redirect" }],
161
222
  description: "Connect a Linear workspace.",
162
223
  id: "linear",
163
224
  name: "Linear",
164
225
  })
165
226
 
166
227
  export const microsoftService = defineIntegrationService({
167
- connectionMethods: [{ id: "default", name: "OAuth", type: "redirect" }],
228
+ connectionMethods: [{ id: "oauth", name: "OAuth", type: "redirect" }],
168
229
  description: "Connect a Microsoft account.",
169
230
  id: "microsoft",
170
231
  name: "Microsoft",
@@ -217,7 +278,7 @@ export const postgresService = defineIntegrationService({
217
278
  required: true,
218
279
  },
219
280
  ],
220
- id: "default",
281
+ id: "credentials",
221
282
  name: "Credentials",
222
283
  type: "form",
223
284
  },
@@ -251,14 +312,14 @@ export const scrapflyService = defineApiKeyService({
251
312
  })
252
313
 
253
314
  export const slackService = defineIntegrationService({
254
- connectionMethods: [{ id: "default", name: "OAuth", type: "redirect" }],
315
+ connectionMethods: [{ id: "oauth", name: "OAuth", type: "redirect" }],
255
316
  description: "Install the Automate.ax bot in a Slack workspace.",
256
317
  id: "slack",
257
318
  name: "Slack",
258
319
  })
259
320
 
260
321
  export const tidycalService = defineIntegrationService({
261
- connectionMethods: [{ id: "default", name: "OAuth", type: "redirect" }],
322
+ connectionMethods: [{ id: "oauth", name: "OAuth", type: "redirect" }],
262
323
  description: "Connect a TidyCal account.",
263
324
  id: "tidycal",
264
325
  name: "TidyCal",
@@ -271,7 +332,7 @@ export const togetheraiService = defineApiKeyService({
271
332
  })
272
333
 
273
334
  export const trelloService = defineIntegrationService({
274
- connectionMethods: [{ id: "default", name: "OAuth", type: "redirect" }],
335
+ connectionMethods: [{ id: "oauth", name: "OAuth", type: "redirect" }],
275
336
  description: "Connect a Trello account.",
276
337
  id: "trello",
277
338
  name: "Trello",
@@ -331,7 +392,9 @@ export const integrationCatalog = defineIntegrationCatalog([
331
392
  asanaService,
332
393
  brevoService,
333
394
  cerebrasService,
395
+ chatgptService,
334
396
  cloudflareService,
397
+ codexService,
335
398
  cohereService,
336
399
  deepinfraService,
337
400
  deepseekService,
@@ -399,7 +462,7 @@ function defineApiKeyService<const TId extends string>(
399
462
  placeholder: service.placeholder ?? "API key",
400
463
  },
401
464
  ],
402
- id: "default",
465
+ id: "api-key",
403
466
  name: "API key",
404
467
  type: "form",
405
468
  },
package/src/index.ts CHANGED
@@ -5,7 +5,9 @@ export {
5
5
  asanaService,
6
6
  brevoService,
7
7
  cerebrasService,
8
+ chatgptService,
8
9
  cloudflareService,
10
+ codexService,
9
11
  cohereService,
10
12
  deepinfraService,
11
13
  deepseekService,
@@ -1,4 +1,3 @@
1
- import { airtableService } from "../catalog"
2
1
  import type { IntegrationAccountRequirement, TriggerDefinition } from "../types"
3
2
 
4
3
  const AIRTABLE_ACCOUNT = {
@@ -12,7 +11,7 @@ const AIRTABLE_ACCOUNT = {
12
11
  ],
13
12
  },
14
13
  ],
15
- serviceId: airtableService.id,
14
+ serviceId: "airtable",
16
15
  } as const satisfies IntegrationAccountRequirement
17
16
 
18
17
  export const airtableTriggerDefinitions = {
@@ -1,4 +1,3 @@
1
- import { asanaService } from "../catalog"
2
1
  import type { IntegrationAccountRequirement, TriggerDefinition } from "../types"
3
2
 
4
3
  const ASANA_ACCOUNT = {
@@ -7,7 +6,7 @@ const ASANA_ACCOUNT = {
7
6
  requiredScopes: [],
8
7
  },
9
8
  ],
10
- serviceId: asanaService.id,
9
+ serviceId: "asana",
11
10
  } as const satisfies IntegrationAccountRequirement
12
11
 
13
12
  export const asanaTriggerDefinitions = {
@@ -1,4 +1,3 @@
1
- import { brevoService } from "../catalog"
2
1
  import type { IntegrationAccountRequirement, TriggerDefinition } from "../types"
3
2
 
4
3
  const BREVO_ACCOUNT = {
@@ -7,7 +6,7 @@ const BREVO_ACCOUNT = {
7
6
  requiredScopes: [],
8
7
  },
9
8
  ],
10
- serviceId: brevoService.id,
9
+ serviceId: "brevo",
11
10
  } as const satisfies IntegrationAccountRequirement
12
11
 
13
12
  export const brevoTriggerDefinitions = {
@@ -0,0 +1,361 @@
1
+ import type { TriggerDefinition } from "../types"
2
+ import { sentenceCase } from "./name"
3
+ import * as z from "zod/mini"
4
+
5
+ const EMAIL_SCHEMA = z.email()
6
+ const URL_SCHEMA = z.url()
7
+ const FIELD_NAME_SCHEMA = z
8
+ .string()
9
+ .check(z.trim(), z.minLength(1), z.maxLength(100))
10
+ const FIELD_LABEL_SCHEMA = z
11
+ .string()
12
+ .check(z.trim(), z.minLength(1), z.maxLength(255))
13
+ const FIELD_DESCRIPTION_SCHEMA = z.string().check(z.maxLength(2_000))
14
+ const FIELD_LENGTH_SCHEMA = z.int().check(z.nonnegative())
15
+ const DASHBOARD_RUN_FIELD_BASE_SCHEMA = {
16
+ description: z.optional(FIELD_DESCRIPTION_SCHEMA),
17
+ label: z.optional(FIELD_LABEL_SCHEMA),
18
+ name: FIELD_NAME_SCHEMA,
19
+ }
20
+ const DASHBOARD_RUN_TEXT_FIELD_SCHEMA = z.object({
21
+ ...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
22
+ defaultValue: z.optional(z.string()),
23
+ maxLength: z.optional(FIELD_LENGTH_SCHEMA),
24
+ minLength: z.optional(FIELD_LENGTH_SCHEMA),
25
+ placeholder: z.optional(z.string()),
26
+ required: z.prefault(z.boolean(), true),
27
+ type: z.enum(["email", "phone", "text", "textarea", "url"]),
28
+ })
29
+ const DASHBOARD_RUN_NUMBER_FIELD_SCHEMA = z.object({
30
+ ...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
31
+ defaultValue: z.optional(z.number()),
32
+ max: z.optional(z.number()),
33
+ min: z.optional(z.number()),
34
+ placeholder: z.optional(z.string()),
35
+ required: z.prefault(z.boolean(), true),
36
+ step: z.prefault(z.number().check(z.positive()), 1),
37
+ type: z.literal("number"),
38
+ })
39
+ const DASHBOARD_RUN_DATE_FIELD_SCHEMA = z.object({
40
+ ...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
41
+ defaultValue: z.optional(z.iso.date()),
42
+ max: z.optional(z.iso.date()),
43
+ min: z.optional(z.iso.date()),
44
+ required: z.prefault(z.boolean(), true),
45
+ step: z.prefault(z.int().check(z.positive()), 1),
46
+ type: z.literal("date"),
47
+ })
48
+ const DASHBOARD_RUN_DATETIME_FIELD_SCHEMA = z.object({
49
+ ...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
50
+ defaultValue: z.optional(z.iso.datetime({ local: true })),
51
+ max: z.optional(z.iso.datetime({ local: true })),
52
+ min: z.optional(z.iso.datetime({ local: true })),
53
+ required: z.prefault(z.boolean(), true),
54
+ step: z.prefault(z.number().check(z.positive()), 60),
55
+ type: z.literal("datetime"),
56
+ })
57
+ const DASHBOARD_RUN_CHOICE_FIELD_SCHEMA = {
58
+ ...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
59
+ defaultValue: z.optional(FIELD_NAME_SCHEMA),
60
+ options: z
61
+ .array(
62
+ z.object({
63
+ label: FIELD_LABEL_SCHEMA,
64
+ value: FIELD_NAME_SCHEMA,
65
+ }),
66
+ )
67
+ .check(z.minLength(1)),
68
+ placeholder: z.optional(z.string()),
69
+ required: z.prefault(z.boolean(), true),
70
+ }
71
+ const DASHBOARD_RUN_SELECT_FIELD_SCHEMA = z.object({
72
+ ...DASHBOARD_RUN_CHOICE_FIELD_SCHEMA,
73
+ type: z.literal("select"),
74
+ })
75
+ const DASHBOARD_RUN_RADIO_FIELD_SCHEMA = z.object({
76
+ ...DASHBOARD_RUN_CHOICE_FIELD_SCHEMA,
77
+ type: z.literal("radio"),
78
+ })
79
+ const DASHBOARD_RUN_MULTI_SELECT_FIELD_SCHEMA = z.object({
80
+ ...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
81
+ defaultValue: z.optional(z.array(FIELD_NAME_SCHEMA)),
82
+ options: z
83
+ .array(
84
+ z.object({
85
+ label: FIELD_LABEL_SCHEMA,
86
+ value: FIELD_NAME_SCHEMA,
87
+ }),
88
+ )
89
+ .check(z.minLength(1)),
90
+ placeholder: z.optional(z.string()),
91
+ required: z.prefault(z.boolean(), true),
92
+ type: z.literal("multi-select"),
93
+ })
94
+ const DASHBOARD_RUN_CHECKBOX_FIELD_SCHEMA = z.object({
95
+ ...DASHBOARD_RUN_FIELD_BASE_SCHEMA,
96
+ defaultValue: z.prefault(z.boolean(), false),
97
+ required: z.prefault(z.boolean(), false),
98
+ type: z.literal("checkbox"),
99
+ })
100
+ const DASHBOARD_RUN_FIELD_SCHEMA = z.pipe(
101
+ z.discriminatedUnion("type", [
102
+ DASHBOARD_RUN_TEXT_FIELD_SCHEMA,
103
+ DASHBOARD_RUN_NUMBER_FIELD_SCHEMA,
104
+ DASHBOARD_RUN_DATE_FIELD_SCHEMA,
105
+ DASHBOARD_RUN_DATETIME_FIELD_SCHEMA,
106
+ DASHBOARD_RUN_SELECT_FIELD_SCHEMA,
107
+ DASHBOARD_RUN_RADIO_FIELD_SCHEMA,
108
+ DASHBOARD_RUN_MULTI_SELECT_FIELD_SCHEMA,
109
+ DASHBOARD_RUN_CHECKBOX_FIELD_SCHEMA,
110
+ ]),
111
+ z.transform((field) => ({
112
+ ...field,
113
+ label:
114
+ field.label ??
115
+ `${sentenceCase(field.name)}${field.type === "checkbox" ? "?" : ""}`,
116
+ })),
117
+ )
118
+ const DASHBOARD_RUN_FIELDS_SCHEMA = z.array(DASHBOARD_RUN_FIELD_SCHEMA).check(
119
+ z.refine(
120
+ (fields) =>
121
+ new Set(fields.map((field) => field.name)).size === fields.length,
122
+ "Dashboard run field names must be unique.",
123
+ ),
124
+ z.refine(
125
+ (fields) => fields.every(isDashboardRunFieldDefaultValid),
126
+ "Dashboard run field defaults must satisfy their field constraints.",
127
+ ),
128
+ )
129
+
130
+ export const DASHBOARD_RUN_CONFIG_SCHEMA = z.object({
131
+ description: z.optional(FIELD_DESCRIPTION_SCHEMA),
132
+ fields: z.prefault(DASHBOARD_RUN_FIELDS_SCHEMA, []),
133
+ submitLabel: z.prefault(
134
+ z.string().check(z.trim(), z.minLength(1), z.maxLength(100)),
135
+ "Run",
136
+ ),
137
+ title: z.string().check(z.trim(), z.minLength(1), z.maxLength(255)),
138
+ })
139
+
140
+ export const dashboardRunTriggerDefinition = {
141
+ getDetails: ({ config }) => [
142
+ {
143
+ label: "Run form",
144
+ value: DASHBOARD_RUN_CONFIG_SCHEMA.parse(config).title,
145
+ },
146
+ ],
147
+ icon: "automation",
148
+ name: "Dashboard run",
149
+ type: "dashboard.run",
150
+ } as const satisfies TriggerDefinition
151
+
152
+ interface DashboardRunFieldBase {
153
+ /** Supporting text shown below the field. */
154
+ description?: string
155
+
156
+ /** Visible field label. Inferred from `name` when omitted. */
157
+ label?: string
158
+
159
+ /** Property name used in submitted trigger data. */
160
+ name: string
161
+
162
+ /** Whether the form must contain a value. Defaults to true. */
163
+ required?: boolean
164
+ }
165
+
166
+ export type DashboardRunField =
167
+ | (DashboardRunFieldBase & {
168
+ defaultValue?: string
169
+ maxLength?: number
170
+ minLength?: number
171
+ placeholder?: string
172
+ type: "email" | "phone" | "text" | "textarea" | "url"
173
+ })
174
+ | (DashboardRunFieldBase & {
175
+ defaultValue?: number
176
+ max?: number
177
+ min?: number
178
+ placeholder?: string
179
+
180
+ /** Increment used by the number input. Defaults to 1. */
181
+ step?: number
182
+ type: "number"
183
+ })
184
+ | (DashboardRunFieldBase & {
185
+ /** Initial local date in `YYYY-MM-DD` format. */
186
+ defaultValue?: string
187
+ max?: string
188
+ min?: string
189
+
190
+ /** Allowed increment in days. Defaults to 1. */
191
+ step?: number
192
+ type: "date"
193
+ })
194
+ | (DashboardRunFieldBase & {
195
+ /** Initial local date and time in `YYYY-MM-DDTHH:mm` format. */
196
+ defaultValue?: string
197
+ max?: string
198
+ min?: string
199
+
200
+ /** Allowed increment in seconds. Defaults to 60. */
201
+ step?: number
202
+ type: "datetime"
203
+ })
204
+ | (DashboardRunFieldBase & {
205
+ defaultValue?: string
206
+ options: readonly { label: string; value: string }[]
207
+ placeholder?: string
208
+ type: "select"
209
+ })
210
+ | (DashboardRunFieldBase & {
211
+ defaultValue?: string
212
+ options: readonly { label: string; value: string }[]
213
+ type: "radio"
214
+ })
215
+ | (DashboardRunFieldBase & {
216
+ defaultValue?: readonly string[]
217
+ options: readonly { label: string; value: string }[]
218
+ placeholder?: string
219
+ type: "multi-select"
220
+ })
221
+ | (DashboardRunFieldBase & {
222
+ /** Initial checked state. Defaults to false. */
223
+ defaultValue?: boolean
224
+
225
+ /** Whether the checkbox must be checked. Defaults to false. */
226
+ required?: boolean
227
+ type: "checkbox"
228
+ })
229
+
230
+ export interface DashboardRunConfig<
231
+ TFields extends readonly DashboardRunField[] = readonly DashboardRunField[],
232
+ > {
233
+ /** Supporting text shown below the form title. */
234
+ description?: string
235
+
236
+ /** Ordered fields. Omit to run immediately. */
237
+ fields?: TFields
238
+
239
+ /** Submit button text. Defaults to "Run". */
240
+ submitLabel?: string
241
+
242
+ /** Form heading. */
243
+ title: string
244
+ }
245
+
246
+ export interface DashboardRunEndpointOptions {
247
+ appOrigin: string
248
+ automationId: string
249
+ hookSlot: number
250
+ scopePath?: readonly number[]
251
+ }
252
+
253
+ /**
254
+ * Returns the organization-authenticated submission endpoint for one dashboard
255
+ * run.
256
+ *
257
+ * @param options - Public origin and trigger identity.
258
+ */
259
+ export function getDashboardRunEndpoint(options: DashboardRunEndpointOptions) {
260
+ return new URL(
261
+ `/api/dashboard-runs/${getDashboardRunEndpointKey(options)}`,
262
+ options.appOrigin,
263
+ ).toString()
264
+ }
265
+
266
+ /**
267
+ * Returns the durable endpoint identity for one dashboard run trigger.
268
+ *
269
+ * @param options - Trigger and owning automation identity.
270
+ */
271
+ export function getDashboardRunEndpointKey(
272
+ options: Omit<DashboardRunEndpointOptions, "appOrigin">,
273
+ ) {
274
+ return `${options.automationId}:${[
275
+ ...(options.scopePath ?? []),
276
+ options.hookSlot,
277
+ ].join(".")}`
278
+ }
279
+
280
+ /**
281
+ * Checks a configured default against the same constraints as submitted data.
282
+ *
283
+ * @param field - Field definition to validate.
284
+ */
285
+ function isDashboardRunFieldDefaultValid(field: DashboardRunField) {
286
+ if (field.type === "checkbox" || field.defaultValue === undefined) return true
287
+
288
+ if (field.type === "multi-select") {
289
+ if (field.required !== false && field.defaultValue.length === 0)
290
+ return false
291
+ return field.defaultValue.every((value) =>
292
+ field.options.some((option) => option.value === value),
293
+ )
294
+ }
295
+
296
+ if (field.type === "radio" || field.type === "select") {
297
+ return field.options.some((option) => option.value === field.defaultValue)
298
+ }
299
+
300
+ if (field.type === "number") {
301
+ return (
302
+ (field.min === undefined || field.defaultValue >= field.min) &&
303
+ (field.max === undefined || field.defaultValue <= field.max) &&
304
+ !isDashboardRunStepMismatch(
305
+ field.defaultValue,
306
+ field.min ?? field.defaultValue,
307
+ field.step ?? 1,
308
+ )
309
+ )
310
+ }
311
+
312
+ if (field.type === "date" || field.type === "datetime") {
313
+ const defaultValue = parseDashboardRunDateValue(
314
+ field.type,
315
+ field.defaultValue,
316
+ )
317
+ return (
318
+ (field.min === undefined ||
319
+ defaultValue >= parseDashboardRunDateValue(field.type, field.min)) &&
320
+ (field.max === undefined ||
321
+ defaultValue <= parseDashboardRunDateValue(field.type, field.max)) &&
322
+ !isDashboardRunStepMismatch(
323
+ defaultValue,
324
+ parseDashboardRunDateValue(field.type, field.min ?? field.defaultValue),
325
+ (field.step ?? (field.type === "date" ? 1 : 60)) *
326
+ (field.type === "date" ? 86_400_000 : 1_000),
327
+ )
328
+ )
329
+ }
330
+
331
+ const defaultValue = field.defaultValue.trim()
332
+ return (
333
+ (defaultValue.length > 0 || field.required === false) &&
334
+ (field.minLength === undefined || defaultValue.length >= field.minLength) &&
335
+ (field.maxLength === undefined || defaultValue.length <= field.maxLength) &&
336
+ (field.type !== "email" || EMAIL_SCHEMA.safeParse(defaultValue).success) &&
337
+ (field.type !== "url" || URL_SCHEMA.safeParse(defaultValue).success)
338
+ )
339
+ }
340
+
341
+ /**
342
+ * Checks whether a value falls outside an allowed step interval.
343
+ *
344
+ * @param value - Configured default value.
345
+ * @param base - Value from which step intervals begin.
346
+ * @param step - Allowed interval size.
347
+ */
348
+ function isDashboardRunStepMismatch(value: number, base: number, step: number) {
349
+ const intervals = (value - base) / step
350
+ return Math.abs(intervals - Math.round(intervals)) > 1e-9
351
+ }
352
+
353
+ /**
354
+ * Converts a validated local date or date-time string to a UTC number.
355
+ *
356
+ * @param type - Temporal field type.
357
+ * @param value - Local ISO value to convert.
358
+ */
359
+ function parseDashboardRunDateValue(type: "date" | "datetime", value: string) {
360
+ return Date.parse(type === "date" ? `${value}T00:00:00Z` : `${value}Z`)
361
+ }
@@ -0,0 +1,69 @@
1
+ import type { TriggerDefinition } from "../types"
2
+ import * as z from "zod/mini"
3
+
4
+ const HTTP_PRESENTATION_CONFIG_SCHEMA = z.object({
5
+ scope: z.prefault(z.enum(["trigger", "automation", "project"]), "trigger"),
6
+ })
7
+
8
+ export const httpRequestTriggerDefinition = {
9
+ getPrimary: ({
10
+ appOrigin,
11
+ automationId,
12
+ config,
13
+ hookSlot,
14
+ projectId,
15
+ scopePath,
16
+ }) => ({
17
+ copyable: true,
18
+ value: getHttpTriggerEndpoint({
19
+ appOrigin,
20
+ automationId,
21
+ hookSlot,
22
+ projectId,
23
+ scope: HTTP_PRESENTATION_CONFIG_SCHEMA.parse(config).scope,
24
+ scopePath,
25
+ }),
26
+ }),
27
+ icon: "webhook",
28
+ name: "HTTP request",
29
+ type: "http.request",
30
+ } as const satisfies TriggerDefinition
31
+
32
+ export type HttpTriggerScope = "trigger" | "automation" | "project"
33
+
34
+ export interface HttpTriggerEndpointOptions {
35
+ appOrigin: string
36
+ automationId: string
37
+ hookSlot: number
38
+ projectId: string
39
+ scope: HttpTriggerScope
40
+ scopePath?: readonly number[]
41
+ }
42
+
43
+ /**
44
+ * Returns the public URL for one deployed HTTP trigger.
45
+ *
46
+ * @param options - Public origin and trigger identity.
47
+ */
48
+ export function getHttpTriggerEndpoint(options: HttpTriggerEndpointOptions) {
49
+ return new URL(
50
+ `/x/${getHttpTriggerEndpointKey(options)}/`,
51
+ options.appOrigin,
52
+ ).toString()
53
+ }
54
+
55
+ /**
56
+ * Returns the durable endpoint identity for one configured HTTP scope.
57
+ *
58
+ * @param options - Trigger and owning resource identity.
59
+ */
60
+ export function getHttpTriggerEndpointKey(
61
+ options: Omit<HttpTriggerEndpointOptions, "appOrigin">,
62
+ ) {
63
+ if (options.scope === "project") return options.projectId
64
+ if (options.scope === "automation") return options.automationId
65
+ return `${options.automationId}:${[
66
+ ...(options.scopePath ?? []),
67
+ options.hookSlot,
68
+ ].join(".")}`
69
+ }
@@ -0,0 +1,18 @@
1
+ import type { TriggerDefinition } from "../types"
2
+ import * as z from "zod/mini"
3
+
4
+ const INVOCATION_PRESENTATION_CONFIG_SCHEMA = z.object({
5
+ entrypoint: z.string(),
6
+ })
7
+
8
+ export const automationInvokedTriggerDefinition = {
9
+ getDetails: ({ config }) => [
10
+ {
11
+ label: "Entrypoint",
12
+ value: INVOCATION_PRESENTATION_CONFIG_SCHEMA.parse(config).entrypoint,
13
+ },
14
+ ],
15
+ icon: "automation",
16
+ name: "Invocation",
17
+ type: "automation.invoked",
18
+ } as const satisfies TriggerDefinition