@automate.ax/integration-contracts 0.55.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/airtable/api.d.ts +19 -0
- package/dist/airtable/api.js +44 -0
- package/dist/airtable/index.d.ts +353 -0
- package/dist/airtable/index.js +32 -0
- package/dist/airtable/schemas.d.ts +716 -0
- package/dist/airtable/schemas.js +184 -0
- package/dist/asana/api.d.ts +70 -0
- package/dist/asana/api.js +119 -0
- package/dist/asana/index.d.ts +384 -0
- package/dist/asana/index.js +38 -0
- package/dist/asana/schemas.d.ts +1060 -0
- package/dist/asana/schemas.js +512 -0
- package/dist/brevo/api.d.ts +31 -0
- package/dist/brevo/api.js +64 -0
- package/dist/brevo/index.d.ts +822 -0
- package/dist/brevo/index.js +51 -0
- package/dist/brevo/schemas.d.ts +1217 -0
- package/dist/brevo/schemas.js +332 -0
- package/dist/github/index.d.ts +37 -0
- package/dist/github/index.js +106 -0
- package/dist/github/schemas.d.ts +8014 -0
- package/dist/github/schemas.js +113 -0
- package/dist/gmail/gmail.d.ts +172 -0
- package/dist/gmail/gmail.js +405 -0
- package/dist/gmail/index.d.ts +262 -0
- package/dist/gmail/index.js +23 -0
- package/dist/gmail/schemas.d.ts +444 -0
- package/dist/gmail/schemas.js +242 -0
- package/dist/google-calendar/event-schemas.d.ts +117 -0
- package/dist/google-calendar/event-schemas.js +13 -0
- package/dist/google-calendar/google-calendar.d.ts +147 -0
- package/dist/google-calendar/google-calendar.js +583 -0
- package/dist/google-calendar/index.d.ts +365 -0
- package/dist/google-calendar/index.js +24 -0
- package/dist/google-calendar/schemas.d.ts +592 -0
- package/dist/google-calendar/schemas.js +379 -0
- package/dist/google-forms/event-schemas.d.ts +105 -0
- package/dist/google-forms/event-schemas.js +20 -0
- package/dist/google-forms/google-forms.d.ts +243 -0
- package/dist/google-forms/google-forms.js +581 -0
- package/dist/google-forms/index.d.ts +141 -0
- package/dist/google-forms/index.js +20 -0
- package/dist/google-forms/schemas.d.ts +618 -0
- package/dist/google-forms/schemas.js +383 -0
- package/dist/linear/api.d.ts +63 -0
- package/dist/linear/api.js +88 -0
- package/dist/linear/index.d.ts +1338 -0
- package/dist/linear/index.js +55 -0
- package/dist/linear/schemas.d.ts +1795 -0
- package/dist/linear/schemas.js +760 -0
- package/dist/outlook/graph.d.ts +34 -0
- package/dist/outlook/graph.js +98 -0
- package/dist/outlook/index.d.ts +115 -0
- package/dist/outlook/index.js +11 -0
- package/dist/outlook/schemas.d.ts +529 -0
- package/dist/outlook/schemas.js +312 -0
- package/dist/resend/index.d.ts +707 -0
- package/dist/resend/index.js +54 -0
- package/dist/resend/schemas.d.ts +1033 -0
- package/dist/resend/schemas.js +377 -0
- package/dist/slack/index.d.ts +151 -0
- package/dist/slack/index.js +22 -0
- package/dist/slack/schemas.d.ts +641 -0
- package/dist/slack/schemas.js +581 -0
- package/dist/teams/graph.d.ts +33 -0
- package/dist/teams/graph.js +95 -0
- package/dist/teams/index.d.ts +164 -0
- package/dist/teams/index.js +21 -0
- package/dist/teams/schemas.d.ts +675 -0
- package/dist/teams/schemas.js +365 -0
- package/dist/trello/api.d.ts +69 -0
- package/dist/trello/api.js +140 -0
- package/dist/trello/event-schemas.d.ts +1101 -0
- package/dist/trello/event-schemas.js +233 -0
- package/dist/trello/index.d.ts +721 -0
- package/dist/trello/index.js +35 -0
- package/dist/trello/schemas.d.ts +283 -0
- package/dist/trello/schemas.js +401 -0
- package/dist/triggers.d.ts +26 -0
- package/dist/triggers.js +33 -0
- package/dist/vercel/index.d.ts +1065 -0
- package/dist/vercel/index.js +114 -0
- package/dist/vercel/schemas.d.ts +1518 -0
- package/dist/vercel/schemas.js +335 -0
- package/dist/whatsapp/api.d.ts +62 -0
- package/dist/whatsapp/api.js +121 -0
- package/dist/whatsapp/index.d.ts +614 -0
- package/dist/whatsapp/index.js +35 -0
- package/dist/whatsapp/schemas.d.ts +926 -0
- package/dist/whatsapp/schemas.js +326 -0
- package/package.json +169 -0
- package/src/airtable/api.ts +66 -0
- package/src/airtable/index.ts +41 -0
- package/src/airtable/schemas.ts +231 -0
- package/src/asana/api.ts +171 -0
- package/src/asana/index.ts +49 -0
- package/src/asana/schemas.ts +655 -0
- package/src/brevo/api.ts +89 -0
- package/src/brevo/index.ts +66 -0
- package/src/brevo/schemas.ts +449 -0
- package/src/github/index.ts +217 -0
- package/src/github/schemas.ts +435 -0
- package/src/gmail/gmail.ts +577 -0
- package/src/gmail/index.ts +26 -0
- package/src/gmail/schemas.ts +327 -0
- package/src/google-calendar/event-schemas.ts +16 -0
- package/src/google-calendar/google-calendar.ts +727 -0
- package/src/google-calendar/index.ts +27 -0
- package/src/google-calendar/schemas.ts +529 -0
- package/src/google-forms/event-schemas.ts +26 -0
- package/src/google-forms/google-forms.ts +683 -0
- package/src/google-forms/index.ts +23 -0
- package/src/google-forms/schemas.ts +499 -0
- package/src/linear/api.ts +141 -0
- package/src/linear/index.ts +71 -0
- package/src/linear/schemas.ts +1060 -0
- package/src/outlook/graph.ts +132 -0
- package/src/outlook/index.ts +14 -0
- package/src/outlook/schemas.ts +388 -0
- package/src/resend/index.ts +70 -0
- package/src/resend/schemas.ts +462 -0
- package/src/slack/index.ts +29 -0
- package/src/slack/schemas.ts +737 -0
- package/src/teams/graph.ts +130 -0
- package/src/teams/index.ts +27 -0
- package/src/teams/schemas.ts +463 -0
- package/src/trello/api.ts +190 -0
- package/src/trello/event-schemas.ts +290 -0
- package/src/trello/index.ts +45 -0
- package/src/trello/schemas.ts +507 -0
- package/src/triggers.ts +68 -0
- package/src/vercel/index.ts +147 -0
- package/src/vercel/schemas.ts +594 -0
- package/src/whatsapp/api.ts +171 -0
- package/src/whatsapp/index.ts +46 -0
- package/src/whatsapp/schemas.ts +341 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { z } from "zod"
|
|
2
|
+
|
|
3
|
+
const TRELLO_API_BASE_URL = "https://api.trello.com/1/"
|
|
4
|
+
const TRELLO_API_ORIGIN = new URL(TRELLO_API_BASE_URL).origin
|
|
5
|
+
const TRELLO_SECRET_SCHEMA = z.object({
|
|
6
|
+
apiKey: z.string().min(1),
|
|
7
|
+
token: z.string().min(1),
|
|
8
|
+
})
|
|
9
|
+
const TRELLO_ERROR_SCHEMA = z.looseObject({
|
|
10
|
+
message: z.string().optional(),
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
/** Scalar value serialized into one Trello query parameter. */
|
|
14
|
+
type TrelloQueryValue = boolean | number | string | undefined
|
|
15
|
+
|
|
16
|
+
/** Options for one authenticated Trello REST request. */
|
|
17
|
+
export interface TrelloRequestOptions<TSchema extends z.ZodType> {
|
|
18
|
+
/** JSON request body for endpoints that accept one. */
|
|
19
|
+
body?: unknown
|
|
20
|
+
|
|
21
|
+
/** HTTP verb. Defaults to `GET`. */
|
|
22
|
+
method?: "DELETE" | "GET" | "POST" | "PUT"
|
|
23
|
+
|
|
24
|
+
/** Query parameters appended to the request URL. */
|
|
25
|
+
query?: Record<string, TrelloQueryValue>
|
|
26
|
+
|
|
27
|
+
/** Schema that validates and types the successful response. */
|
|
28
|
+
responseSchema: TSchema
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Authenticated raw Trello REST helper. */
|
|
32
|
+
export interface TrelloApi {
|
|
33
|
+
/**
|
|
34
|
+
* Calls any Trello REST endpoint and validates its successful response.
|
|
35
|
+
*
|
|
36
|
+
* @param path - Relative path below Trello's `/1` API root.
|
|
37
|
+
* @param options - Request data and successful response schema.
|
|
38
|
+
*/
|
|
39
|
+
request<TSchema extends z.ZodType>(
|
|
40
|
+
path: string,
|
|
41
|
+
options: TrelloRequestOptions<TSchema>,
|
|
42
|
+
): Promise<z.output<TSchema>>
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Structured Trello REST request error. */
|
|
46
|
+
export class TrelloApiError extends Error {
|
|
47
|
+
/** Provider error body, when Trello returned text. */
|
|
48
|
+
readonly providerMessage?: string
|
|
49
|
+
|
|
50
|
+
/** Retry delay from Trello's `Retry-After` header, in seconds. */
|
|
51
|
+
readonly retryAfter?: number
|
|
52
|
+
|
|
53
|
+
/** HTTP status returned by Trello. */
|
|
54
|
+
readonly status: number
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Creates a structured Trello API error.
|
|
58
|
+
*
|
|
59
|
+
* @param options - Provider and transport error details.
|
|
60
|
+
* @param options.providerMessage - Provider error body.
|
|
61
|
+
* @param options.retryAfter - Retry delay in seconds.
|
|
62
|
+
* @param options.status - HTTP response status.
|
|
63
|
+
*/
|
|
64
|
+
constructor(options: {
|
|
65
|
+
providerMessage?: string
|
|
66
|
+
retryAfter?: number
|
|
67
|
+
status: number
|
|
68
|
+
}) {
|
|
69
|
+
super(
|
|
70
|
+
options.providerMessage
|
|
71
|
+
? `Trello API error (${options.status}): ${options.providerMessage}`
|
|
72
|
+
: `Trello API request failed with status ${options.status}.`,
|
|
73
|
+
)
|
|
74
|
+
this.name = "TrelloApiError"
|
|
75
|
+
this.providerMessage = options.providerMessage
|
|
76
|
+
this.retryAfter = options.retryAfter
|
|
77
|
+
this.status = options.status
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Creates a raw authenticated Trello REST helper.
|
|
83
|
+
*
|
|
84
|
+
* Use this escape hatch for provider endpoints that do not yet have a packaged
|
|
85
|
+
* action. Trello authenticates requests with the integration API key and user
|
|
86
|
+
* token, and the caller supplies a response schema for boundary validation.
|
|
87
|
+
*
|
|
88
|
+
* @param secret - Resolved Trello integration secret.
|
|
89
|
+
*/
|
|
90
|
+
export function getTrelloApi(secret: Record<string, unknown>): TrelloApi {
|
|
91
|
+
const { apiKey, token } = TRELLO_SECRET_SCHEMA.parse(secret)
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
request: async (path, options) => {
|
|
95
|
+
const url = new URL(path.replace(/^\//, ""), TRELLO_API_BASE_URL)
|
|
96
|
+
if (url.origin !== TRELLO_API_ORIGIN) {
|
|
97
|
+
throw new Error("Trello API paths must use the Trello API origin.")
|
|
98
|
+
}
|
|
99
|
+
for (const [name, value] of Object.entries(options.query ?? {})) {
|
|
100
|
+
if (value !== undefined) url.searchParams.set(name, String(value))
|
|
101
|
+
}
|
|
102
|
+
url.searchParams.set("key", apiKey)
|
|
103
|
+
url.searchParams.set("token", token)
|
|
104
|
+
|
|
105
|
+
const headers = new Headers({ Accept: "application/json" })
|
|
106
|
+
if (options.body !== undefined)
|
|
107
|
+
headers.set("Content-Type", "application/json")
|
|
108
|
+
const response = await fetch(url, {
|
|
109
|
+
body:
|
|
110
|
+
options.body === undefined ? undefined : JSON.stringify(options.body),
|
|
111
|
+
headers,
|
|
112
|
+
method: options.method ?? "GET",
|
|
113
|
+
})
|
|
114
|
+
if (!response.ok) {
|
|
115
|
+
const responseText = await response.text()
|
|
116
|
+
const error = TRELLO_ERROR_SCHEMA.safeParse(parseJson(responseText))
|
|
117
|
+
throw new TrelloApiError({
|
|
118
|
+
providerMessage:
|
|
119
|
+
error.success && error.data.message
|
|
120
|
+
? error.data.message
|
|
121
|
+
: responseText || undefined,
|
|
122
|
+
retryAfter: parseRetryAfter(response.headers.get("Retry-After")),
|
|
123
|
+
status: response.status,
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
return options.responseSchema.parse(await response.json())
|
|
127
|
+
},
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Accepts a raw card ID, short link, or standard Trello card URL.
|
|
133
|
+
*
|
|
134
|
+
* @param card - Card reference to normalize.
|
|
135
|
+
*/
|
|
136
|
+
export function normalizeTrelloCardId(card: string) {
|
|
137
|
+
return normalizeTrelloUrlReference(card, "c")
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Accepts a raw board ID, short link, or standard Trello board URL.
|
|
142
|
+
*
|
|
143
|
+
* @param board - Board reference to normalize.
|
|
144
|
+
*/
|
|
145
|
+
export function normalizeTrelloBoardId(board: string) {
|
|
146
|
+
return normalizeTrelloUrlReference(board, "b")
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Extracts a Trello short link from one recognized provider URL.
|
|
151
|
+
*
|
|
152
|
+
* @param value - Raw resource reference.
|
|
153
|
+
* @param resource - Expected Trello URL resource segment.
|
|
154
|
+
*/
|
|
155
|
+
function normalizeTrelloUrlReference(value: string, resource: "b" | "c") {
|
|
156
|
+
const trimmed = value.trim()
|
|
157
|
+
if (!URL.canParse(trimmed)) return trimmed
|
|
158
|
+
|
|
159
|
+
const url = new URL(trimmed)
|
|
160
|
+
if (url.hostname !== "trello.com" && url.hostname !== "www.trello.com") {
|
|
161
|
+
return trimmed
|
|
162
|
+
}
|
|
163
|
+
const parts = url.pathname.split("/").filter(Boolean)
|
|
164
|
+
const resourceIndex = parts.indexOf(resource)
|
|
165
|
+
return resourceIndex === -1 ? trimmed : (parts[resourceIndex + 1] ?? trimmed)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Parses an optional provider JSON error body without masking the HTTP error.
|
|
170
|
+
*
|
|
171
|
+
* @param value - Raw provider response text.
|
|
172
|
+
*/
|
|
173
|
+
function parseJson(value: string): unknown {
|
|
174
|
+
try {
|
|
175
|
+
return JSON.parse(value)
|
|
176
|
+
} catch {
|
|
177
|
+
return undefined
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Parses Trello's integer retry delay header.
|
|
183
|
+
*
|
|
184
|
+
* @param value - Raw `Retry-After` header.
|
|
185
|
+
*/
|
|
186
|
+
function parseRetryAfter(value: string | null) {
|
|
187
|
+
if (value === null) return undefined
|
|
188
|
+
const seconds = Number(value)
|
|
189
|
+
return Number.isFinite(seconds) ? seconds : undefined
|
|
190
|
+
}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { z } from "zod"
|
|
2
|
+
|
|
3
|
+
const TRELLO_JSON_OBJECT_SCHEMA = z.record(z.string(), z.json())
|
|
4
|
+
const TRELLO_RESOURCE_SCHEMA = z
|
|
5
|
+
.looseObject({
|
|
6
|
+
id: z.string(),
|
|
7
|
+
name: z.string().optional(),
|
|
8
|
+
})
|
|
9
|
+
.catchall(z.json())
|
|
10
|
+
const TRELLO_BOARD_SCHEMA = TRELLO_RESOURCE_SCHEMA.extend({
|
|
11
|
+
closed: z.boolean().optional(),
|
|
12
|
+
url: z.string().optional(),
|
|
13
|
+
})
|
|
14
|
+
const TRELLO_CARD_SCHEMA = TRELLO_RESOURCE_SCHEMA.extend({
|
|
15
|
+
closed: z.boolean().optional(),
|
|
16
|
+
idShort: z.number().int().optional(),
|
|
17
|
+
shortLink: z.string().optional(),
|
|
18
|
+
})
|
|
19
|
+
const TRELLO_LIST_SCHEMA = TRELLO_RESOURCE_SCHEMA
|
|
20
|
+
const TRELLO_MEMBER_SCHEMA = TRELLO_RESOURCE_SCHEMA.extend({
|
|
21
|
+
fullName: z.string().optional(),
|
|
22
|
+
username: z.string().optional(),
|
|
23
|
+
})
|
|
24
|
+
const TRELLO_ACTION_DATA_SCHEMA = z
|
|
25
|
+
.looseObject({
|
|
26
|
+
/** Attachment affected by the action, when applicable. */
|
|
27
|
+
attachment: TRELLO_RESOURCE_SCHEMA.extend({
|
|
28
|
+
url: z.string().optional(),
|
|
29
|
+
}).optional(),
|
|
30
|
+
|
|
31
|
+
/** Board affected by the action. */
|
|
32
|
+
board: TRELLO_BOARD_SCHEMA.optional(),
|
|
33
|
+
|
|
34
|
+
/** Card affected by the action, when applicable. */
|
|
35
|
+
card: TRELLO_CARD_SCHEMA.optional(),
|
|
36
|
+
|
|
37
|
+
/** Checklist affected by the action, when applicable. */
|
|
38
|
+
checklist: TRELLO_RESOURCE_SCHEMA.optional(),
|
|
39
|
+
|
|
40
|
+
/** Checklist item affected by the action, when applicable. */
|
|
41
|
+
checkItem: TRELLO_RESOURCE_SCHEMA.optional(),
|
|
42
|
+
|
|
43
|
+
/** List associated with the action. */
|
|
44
|
+
list: TRELLO_LIST_SCHEMA.optional(),
|
|
45
|
+
|
|
46
|
+
/** Destination list for a move action. */
|
|
47
|
+
listAfter: TRELLO_LIST_SCHEMA.optional(),
|
|
48
|
+
|
|
49
|
+
/** Source list for a move action. */
|
|
50
|
+
listBefore: TRELLO_LIST_SCHEMA.optional(),
|
|
51
|
+
|
|
52
|
+
/** Member affected by the action, when applicable. */
|
|
53
|
+
member: TRELLO_MEMBER_SCHEMA.optional(),
|
|
54
|
+
|
|
55
|
+
/** Previous field values supplied for an update action. */
|
|
56
|
+
old: TRELLO_JSON_OBJECT_SCHEMA.optional(),
|
|
57
|
+
|
|
58
|
+
/** Organization affected by the action, when applicable. */
|
|
59
|
+
organization: TRELLO_RESOURCE_SCHEMA.optional(),
|
|
60
|
+
|
|
61
|
+
/** Comment or other action text. */
|
|
62
|
+
text: z.string().optional(),
|
|
63
|
+
})
|
|
64
|
+
.catchall(z.json())
|
|
65
|
+
const TRELLO_CARD_ACTION_DATA_SCHEMA = TRELLO_ACTION_DATA_SCHEMA.extend({
|
|
66
|
+
old: z
|
|
67
|
+
.looseObject({ closed: z.boolean().optional() })
|
|
68
|
+
.catchall(z.json())
|
|
69
|
+
.optional(),
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const TRELLO_WEBHOOK_EVENT_SCHEMA = z.object({
|
|
73
|
+
action: z
|
|
74
|
+
.looseObject({
|
|
75
|
+
data: TRELLO_ACTION_DATA_SCHEMA,
|
|
76
|
+
date: z.iso.datetime({ offset: true }),
|
|
77
|
+
id: z.string(),
|
|
78
|
+
memberCreator: TRELLO_MEMBER_SCHEMA.optional(),
|
|
79
|
+
type: z.string(),
|
|
80
|
+
})
|
|
81
|
+
.catchall(z.json()),
|
|
82
|
+
model: TRELLO_BOARD_SCHEMA,
|
|
83
|
+
webhook: z.looseObject({ id: z.string() }).catchall(z.json()),
|
|
84
|
+
})
|
|
85
|
+
const TRELLO_CARD_CREATED_ACTION_SCHEMA = z.enum([
|
|
86
|
+
"copyCard",
|
|
87
|
+
"convertToCardFromCheckItem",
|
|
88
|
+
"createCard",
|
|
89
|
+
"emailCard",
|
|
90
|
+
])
|
|
91
|
+
const TRELLO_CARD_UPDATED_ACTION_SCHEMA = z.literal("updateCard")
|
|
92
|
+
const TRELLO_CARD_COMMENTED_ACTION_SCHEMA = z.literal("commentCard")
|
|
93
|
+
|
|
94
|
+
export const TRELLO_CARD_EVENT_KINDS = [
|
|
95
|
+
"created",
|
|
96
|
+
"moved",
|
|
97
|
+
"updated",
|
|
98
|
+
"archived",
|
|
99
|
+
"commented",
|
|
100
|
+
] as const
|
|
101
|
+
|
|
102
|
+
export type TrelloCardEventKind = (typeof TRELLO_CARD_EVENT_KINDS)[number]
|
|
103
|
+
|
|
104
|
+
export const TRELLO_BOARD_EVENT_SCHEMA = TRELLO_ACTION_DATA_SCHEMA.extend({
|
|
105
|
+
/** Stable ID of the Trello action that caused this event. */
|
|
106
|
+
actionId: z.string(),
|
|
107
|
+
|
|
108
|
+
/** Trello action category, such as `createCard` or `updateCard`. */
|
|
109
|
+
actionType: z.string(),
|
|
110
|
+
|
|
111
|
+
/** Board affected by the action, falling back to the watched board. */
|
|
112
|
+
board: TRELLO_BOARD_SCHEMA,
|
|
113
|
+
|
|
114
|
+
/** Complete provider webhook envelope. */
|
|
115
|
+
event: TRELLO_WEBHOOK_EVENT_SCHEMA,
|
|
116
|
+
|
|
117
|
+
/** Member responsible for the action, when Trello includes one. */
|
|
118
|
+
memberCreator: TRELLO_MEMBER_SCHEMA.optional(),
|
|
119
|
+
|
|
120
|
+
/** When the underlying Trello action occurred. */
|
|
121
|
+
occurredAt: z.iso.datetime({ offset: true }),
|
|
122
|
+
|
|
123
|
+
/** Provider webhook that delivered the event. */
|
|
124
|
+
webhookId: z.string(),
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
export const TRELLO_CARD_EVENT_SCHEMA = z.object({
|
|
128
|
+
/** Stable ID of the Trello action that caused this event. */
|
|
129
|
+
actionId: z.string(),
|
|
130
|
+
|
|
131
|
+
/** Provider-native Trello action category. */
|
|
132
|
+
actionType: z.string(),
|
|
133
|
+
|
|
134
|
+
/** Board containing the affected card. */
|
|
135
|
+
board: TRELLO_BOARD_EVENT_SCHEMA.shape.board,
|
|
136
|
+
|
|
137
|
+
/** Card affected by the action. */
|
|
138
|
+
card: TRELLO_CARD_SCHEMA,
|
|
139
|
+
|
|
140
|
+
/** Comment text for card-comment events. */
|
|
141
|
+
commentText: z.string().optional(),
|
|
142
|
+
|
|
143
|
+
/** Complete provider webhook envelope. */
|
|
144
|
+
event: TRELLO_WEBHOOK_EVENT_SCHEMA,
|
|
145
|
+
|
|
146
|
+
/** List containing the card after the action. */
|
|
147
|
+
list: TRELLO_LIST_SCHEMA.optional(),
|
|
148
|
+
|
|
149
|
+
/** Member responsible for the action, when supplied by Trello. */
|
|
150
|
+
memberCreator: TRELLO_BOARD_EVENT_SCHEMA.shape.memberCreator,
|
|
151
|
+
|
|
152
|
+
/** When the underlying Trello action occurred. */
|
|
153
|
+
occurredAt: z.iso.datetime({ offset: true }),
|
|
154
|
+
|
|
155
|
+
/** List containing the card before a move. */
|
|
156
|
+
previousList: TRELLO_LIST_SCHEMA.optional(),
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
export const TRELLO_CARD_CREATED_EVENT_SCHEMA = TRELLO_CARD_EVENT_SCHEMA.extend(
|
|
160
|
+
{
|
|
161
|
+
actionType: TRELLO_CARD_CREATED_ACTION_SCHEMA,
|
|
162
|
+
event: trelloWebhookEventSchema(TRELLO_CARD_CREATED_ACTION_SCHEMA),
|
|
163
|
+
},
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
export const TRELLO_CARD_MOVED_EVENT_SCHEMA = TRELLO_CARD_EVENT_SCHEMA.extend({
|
|
167
|
+
actionType: TRELLO_CARD_UPDATED_ACTION_SCHEMA,
|
|
168
|
+
event: trelloWebhookEventSchema(TRELLO_CARD_UPDATED_ACTION_SCHEMA),
|
|
169
|
+
list: TRELLO_LIST_SCHEMA,
|
|
170
|
+
previousList: TRELLO_LIST_SCHEMA,
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
export const TRELLO_CARD_UPDATED_EVENT_SCHEMA = TRELLO_CARD_EVENT_SCHEMA.extend(
|
|
174
|
+
{
|
|
175
|
+
actionType: TRELLO_CARD_UPDATED_ACTION_SCHEMA,
|
|
176
|
+
event: trelloWebhookEventSchema(TRELLO_CARD_UPDATED_ACTION_SCHEMA),
|
|
177
|
+
},
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
export const TRELLO_CARD_ARCHIVED_EVENT_SCHEMA =
|
|
181
|
+
TRELLO_CARD_UPDATED_EVENT_SCHEMA.extend({
|
|
182
|
+
card: TRELLO_CARD_SCHEMA.extend({ closed: z.literal(true) }),
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
export const TRELLO_CARD_COMMENTED_EVENT_SCHEMA =
|
|
186
|
+
TRELLO_CARD_EVENT_SCHEMA.extend({
|
|
187
|
+
actionType: TRELLO_CARD_COMMENTED_ACTION_SCHEMA,
|
|
188
|
+
commentText: z.string(),
|
|
189
|
+
event: trelloWebhookEventSchema(TRELLO_CARD_COMMENTED_ACTION_SCHEMA),
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Normalizes one provider-native Trello board webhook payload.
|
|
194
|
+
*
|
|
195
|
+
* @param value - Untrusted Trello webhook body.
|
|
196
|
+
*/
|
|
197
|
+
export function normalizeTrelloBoardEvent(value: unknown) {
|
|
198
|
+
const event = TRELLO_WEBHOOK_EVENT_SCHEMA.parse(value)
|
|
199
|
+
|
|
200
|
+
return TRELLO_BOARD_EVENT_SCHEMA.parse({
|
|
201
|
+
...event.action.data,
|
|
202
|
+
actionId: event.action.id,
|
|
203
|
+
actionType: event.action.type,
|
|
204
|
+
board: { ...event.model, ...event.action.data.board },
|
|
205
|
+
event,
|
|
206
|
+
memberCreator: event.action.memberCreator,
|
|
207
|
+
occurredAt: event.action.date,
|
|
208
|
+
webhookId: event.webhook.id,
|
|
209
|
+
})
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Classifies one normalized board action into semantic card event categories.
|
|
214
|
+
*
|
|
215
|
+
* A single Trello action can intentionally belong to more than one category;
|
|
216
|
+
* for example, moving a card is also a card update.
|
|
217
|
+
*
|
|
218
|
+
* @param event - Normalized board event received from Trello.
|
|
219
|
+
*/
|
|
220
|
+
export function getTrelloCardEventKinds(
|
|
221
|
+
event: z.output<typeof TRELLO_BOARD_EVENT_SCHEMA>,
|
|
222
|
+
): TrelloCardEventKind[] {
|
|
223
|
+
const data = TRELLO_CARD_ACTION_DATA_SCHEMA.parse(event.event.action.data)
|
|
224
|
+
|
|
225
|
+
return [
|
|
226
|
+
...([
|
|
227
|
+
"createCard",
|
|
228
|
+
"copyCard",
|
|
229
|
+
"convertToCardFromCheckItem",
|
|
230
|
+
"emailCard",
|
|
231
|
+
].includes(event.actionType)
|
|
232
|
+
? (["created"] as const)
|
|
233
|
+
: []),
|
|
234
|
+
...(event.actionType === "updateCard" &&
|
|
235
|
+
data.listBefore !== undefined &&
|
|
236
|
+
data.listAfter !== undefined
|
|
237
|
+
? (["moved"] as const)
|
|
238
|
+
: []),
|
|
239
|
+
...(event.actionType === "updateCard" ? (["updated"] as const) : []),
|
|
240
|
+
...(event.actionType === "updateCard" &&
|
|
241
|
+
data.old?.closed === false &&
|
|
242
|
+
data.card?.closed === true
|
|
243
|
+
? (["archived"] as const)
|
|
244
|
+
: []),
|
|
245
|
+
...(event.actionType === "commentCard" ? (["commented"] as const) : []),
|
|
246
|
+
]
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Promotes provider-native card action data into the stable semantic payload.
|
|
251
|
+
*
|
|
252
|
+
* @param event - Normalized board event classified as a card event.
|
|
253
|
+
* @throws When the classified Trello action does not identify a card.
|
|
254
|
+
*/
|
|
255
|
+
export function normalizeTrelloCardEvent(
|
|
256
|
+
event: z.output<typeof TRELLO_BOARD_EVENT_SCHEMA>,
|
|
257
|
+
) {
|
|
258
|
+
const data = TRELLO_CARD_ACTION_DATA_SCHEMA.parse(event.event.action.data)
|
|
259
|
+
if (!data.card) {
|
|
260
|
+
throw new Error(`Trello ${event.actionType} action did not include a card.`)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return TRELLO_CARD_EVENT_SCHEMA.parse({
|
|
264
|
+
actionId: event.actionId,
|
|
265
|
+
actionType: event.actionType,
|
|
266
|
+
board: event.board,
|
|
267
|
+
card: data.card,
|
|
268
|
+
commentText: data.text,
|
|
269
|
+
event: event.event,
|
|
270
|
+
list: data.listAfter ?? data.list,
|
|
271
|
+
memberCreator: event.memberCreator,
|
|
272
|
+
occurredAt: event.occurredAt,
|
|
273
|
+
previousList: data.listBefore,
|
|
274
|
+
})
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Narrows the provider action type retained under a semantic event.
|
|
279
|
+
*
|
|
280
|
+
* @param actionType - Provider action-type schema for the semantic event.
|
|
281
|
+
*/
|
|
282
|
+
function trelloWebhookEventSchema<TAction extends z.ZodType<string>>(
|
|
283
|
+
actionType: TAction,
|
|
284
|
+
) {
|
|
285
|
+
return TRELLO_WEBHOOK_EVENT_SCHEMA.extend({
|
|
286
|
+
action: TRELLO_WEBHOOK_EVENT_SCHEMA.shape.action.extend({
|
|
287
|
+
type: actionType,
|
|
288
|
+
}),
|
|
289
|
+
})
|
|
290
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { z } from "zod"
|
|
2
|
+
import {
|
|
3
|
+
TRELLO_BOARD_EVENT_SCHEMA,
|
|
4
|
+
TRELLO_CARD_ARCHIVED_EVENT_SCHEMA,
|
|
5
|
+
TRELLO_CARD_COMMENTED_EVENT_SCHEMA,
|
|
6
|
+
TRELLO_CARD_CREATED_EVENT_SCHEMA,
|
|
7
|
+
TRELLO_CARD_MOVED_EVENT_SCHEMA,
|
|
8
|
+
TRELLO_CARD_UPDATED_EVENT_SCHEMA,
|
|
9
|
+
} from "./event-schemas"
|
|
10
|
+
|
|
11
|
+
export * from "./api"
|
|
12
|
+
export * from "./event-schemas"
|
|
13
|
+
export * from "./schemas"
|
|
14
|
+
|
|
15
|
+
/** Canonical Trello board selected by one webhook subscription. */
|
|
16
|
+
export const TRELLO_TRIGGER_CONFIG_SCHEMA = z.object({
|
|
17
|
+
boardId: z.string(),
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
export const trelloTriggerContracts = {
|
|
21
|
+
"trello.board.event": {
|
|
22
|
+
configSchema: TRELLO_TRIGGER_CONFIG_SCHEMA,
|
|
23
|
+
eventSchema: TRELLO_BOARD_EVENT_SCHEMA,
|
|
24
|
+
},
|
|
25
|
+
"trello.card.archived": {
|
|
26
|
+
configSchema: TRELLO_TRIGGER_CONFIG_SCHEMA,
|
|
27
|
+
eventSchema: TRELLO_CARD_ARCHIVED_EVENT_SCHEMA,
|
|
28
|
+
},
|
|
29
|
+
"trello.card.commented": {
|
|
30
|
+
configSchema: TRELLO_TRIGGER_CONFIG_SCHEMA,
|
|
31
|
+
eventSchema: TRELLO_CARD_COMMENTED_EVENT_SCHEMA,
|
|
32
|
+
},
|
|
33
|
+
"trello.card.created": {
|
|
34
|
+
configSchema: TRELLO_TRIGGER_CONFIG_SCHEMA,
|
|
35
|
+
eventSchema: TRELLO_CARD_CREATED_EVENT_SCHEMA,
|
|
36
|
+
},
|
|
37
|
+
"trello.card.moved": {
|
|
38
|
+
configSchema: TRELLO_TRIGGER_CONFIG_SCHEMA,
|
|
39
|
+
eventSchema: TRELLO_CARD_MOVED_EVENT_SCHEMA,
|
|
40
|
+
},
|
|
41
|
+
"trello.card.updated": {
|
|
42
|
+
configSchema: TRELLO_TRIGGER_CONFIG_SCHEMA,
|
|
43
|
+
eventSchema: TRELLO_CARD_UPDATED_EVENT_SCHEMA,
|
|
44
|
+
},
|
|
45
|
+
} as const
|