@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.
Files changed (136) hide show
  1. package/dist/airtable/api.d.ts +19 -0
  2. package/dist/airtable/api.js +44 -0
  3. package/dist/airtable/index.d.ts +353 -0
  4. package/dist/airtable/index.js +32 -0
  5. package/dist/airtable/schemas.d.ts +716 -0
  6. package/dist/airtable/schemas.js +184 -0
  7. package/dist/asana/api.d.ts +70 -0
  8. package/dist/asana/api.js +119 -0
  9. package/dist/asana/index.d.ts +384 -0
  10. package/dist/asana/index.js +38 -0
  11. package/dist/asana/schemas.d.ts +1060 -0
  12. package/dist/asana/schemas.js +512 -0
  13. package/dist/brevo/api.d.ts +31 -0
  14. package/dist/brevo/api.js +64 -0
  15. package/dist/brevo/index.d.ts +822 -0
  16. package/dist/brevo/index.js +51 -0
  17. package/dist/brevo/schemas.d.ts +1217 -0
  18. package/dist/brevo/schemas.js +332 -0
  19. package/dist/github/index.d.ts +37 -0
  20. package/dist/github/index.js +106 -0
  21. package/dist/github/schemas.d.ts +8014 -0
  22. package/dist/github/schemas.js +113 -0
  23. package/dist/gmail/gmail.d.ts +172 -0
  24. package/dist/gmail/gmail.js +405 -0
  25. package/dist/gmail/index.d.ts +262 -0
  26. package/dist/gmail/index.js +23 -0
  27. package/dist/gmail/schemas.d.ts +444 -0
  28. package/dist/gmail/schemas.js +242 -0
  29. package/dist/google-calendar/event-schemas.d.ts +117 -0
  30. package/dist/google-calendar/event-schemas.js +13 -0
  31. package/dist/google-calendar/google-calendar.d.ts +147 -0
  32. package/dist/google-calendar/google-calendar.js +583 -0
  33. package/dist/google-calendar/index.d.ts +365 -0
  34. package/dist/google-calendar/index.js +24 -0
  35. package/dist/google-calendar/schemas.d.ts +592 -0
  36. package/dist/google-calendar/schemas.js +379 -0
  37. package/dist/google-forms/event-schemas.d.ts +105 -0
  38. package/dist/google-forms/event-schemas.js +20 -0
  39. package/dist/google-forms/google-forms.d.ts +243 -0
  40. package/dist/google-forms/google-forms.js +581 -0
  41. package/dist/google-forms/index.d.ts +141 -0
  42. package/dist/google-forms/index.js +20 -0
  43. package/dist/google-forms/schemas.d.ts +618 -0
  44. package/dist/google-forms/schemas.js +383 -0
  45. package/dist/linear/api.d.ts +63 -0
  46. package/dist/linear/api.js +88 -0
  47. package/dist/linear/index.d.ts +1338 -0
  48. package/dist/linear/index.js +55 -0
  49. package/dist/linear/schemas.d.ts +1795 -0
  50. package/dist/linear/schemas.js +760 -0
  51. package/dist/outlook/graph.d.ts +34 -0
  52. package/dist/outlook/graph.js +98 -0
  53. package/dist/outlook/index.d.ts +115 -0
  54. package/dist/outlook/index.js +11 -0
  55. package/dist/outlook/schemas.d.ts +529 -0
  56. package/dist/outlook/schemas.js +312 -0
  57. package/dist/resend/index.d.ts +707 -0
  58. package/dist/resend/index.js +54 -0
  59. package/dist/resend/schemas.d.ts +1033 -0
  60. package/dist/resend/schemas.js +377 -0
  61. package/dist/slack/index.d.ts +151 -0
  62. package/dist/slack/index.js +22 -0
  63. package/dist/slack/schemas.d.ts +641 -0
  64. package/dist/slack/schemas.js +581 -0
  65. package/dist/teams/graph.d.ts +33 -0
  66. package/dist/teams/graph.js +95 -0
  67. package/dist/teams/index.d.ts +164 -0
  68. package/dist/teams/index.js +21 -0
  69. package/dist/teams/schemas.d.ts +675 -0
  70. package/dist/teams/schemas.js +365 -0
  71. package/dist/trello/api.d.ts +69 -0
  72. package/dist/trello/api.js +140 -0
  73. package/dist/trello/event-schemas.d.ts +1101 -0
  74. package/dist/trello/event-schemas.js +233 -0
  75. package/dist/trello/index.d.ts +721 -0
  76. package/dist/trello/index.js +35 -0
  77. package/dist/trello/schemas.d.ts +283 -0
  78. package/dist/trello/schemas.js +401 -0
  79. package/dist/triggers.d.ts +26 -0
  80. package/dist/triggers.js +33 -0
  81. package/dist/vercel/index.d.ts +1065 -0
  82. package/dist/vercel/index.js +114 -0
  83. package/dist/vercel/schemas.d.ts +1518 -0
  84. package/dist/vercel/schemas.js +335 -0
  85. package/dist/whatsapp/api.d.ts +62 -0
  86. package/dist/whatsapp/api.js +121 -0
  87. package/dist/whatsapp/index.d.ts +614 -0
  88. package/dist/whatsapp/index.js +35 -0
  89. package/dist/whatsapp/schemas.d.ts +926 -0
  90. package/dist/whatsapp/schemas.js +326 -0
  91. package/package.json +169 -0
  92. package/src/airtable/api.ts +66 -0
  93. package/src/airtable/index.ts +41 -0
  94. package/src/airtable/schemas.ts +231 -0
  95. package/src/asana/api.ts +171 -0
  96. package/src/asana/index.ts +49 -0
  97. package/src/asana/schemas.ts +655 -0
  98. package/src/brevo/api.ts +89 -0
  99. package/src/brevo/index.ts +66 -0
  100. package/src/brevo/schemas.ts +449 -0
  101. package/src/github/index.ts +217 -0
  102. package/src/github/schemas.ts +435 -0
  103. package/src/gmail/gmail.ts +577 -0
  104. package/src/gmail/index.ts +26 -0
  105. package/src/gmail/schemas.ts +327 -0
  106. package/src/google-calendar/event-schemas.ts +16 -0
  107. package/src/google-calendar/google-calendar.ts +727 -0
  108. package/src/google-calendar/index.ts +27 -0
  109. package/src/google-calendar/schemas.ts +529 -0
  110. package/src/google-forms/event-schemas.ts +26 -0
  111. package/src/google-forms/google-forms.ts +683 -0
  112. package/src/google-forms/index.ts +23 -0
  113. package/src/google-forms/schemas.ts +499 -0
  114. package/src/linear/api.ts +141 -0
  115. package/src/linear/index.ts +71 -0
  116. package/src/linear/schemas.ts +1060 -0
  117. package/src/outlook/graph.ts +132 -0
  118. package/src/outlook/index.ts +14 -0
  119. package/src/outlook/schemas.ts +388 -0
  120. package/src/resend/index.ts +70 -0
  121. package/src/resend/schemas.ts +462 -0
  122. package/src/slack/index.ts +29 -0
  123. package/src/slack/schemas.ts +737 -0
  124. package/src/teams/graph.ts +130 -0
  125. package/src/teams/index.ts +27 -0
  126. package/src/teams/schemas.ts +463 -0
  127. package/src/trello/api.ts +190 -0
  128. package/src/trello/event-schemas.ts +290 -0
  129. package/src/trello/index.ts +45 -0
  130. package/src/trello/schemas.ts +507 -0
  131. package/src/triggers.ts +68 -0
  132. package/src/vercel/index.ts +147 -0
  133. package/src/vercel/schemas.ts +594 -0
  134. package/src/whatsapp/api.ts +171 -0
  135. package/src/whatsapp/index.ts +46 -0
  136. package/src/whatsapp/schemas.ts +341 -0
@@ -0,0 +1,130 @@
1
+ import { z } from "zod"
2
+
3
+ const GRAPH_BASE_URL = "https://graph.microsoft.com/v1.0/"
4
+ const MICROSOFT_SECRET_SCHEMA = z.object({
5
+ accessToken: z.string().min(1),
6
+ })
7
+ const GRAPH_ERROR_SCHEMA = z.looseObject({
8
+ error: z
9
+ .looseObject({
10
+ code: z.string().optional(),
11
+ message: z.string().optional(),
12
+ })
13
+ .optional(),
14
+ })
15
+
16
+ /** Options accepted by the authenticated Teams Graph request helper. */
17
+ export interface TeamsGraphRequestOptions {
18
+ /** JSON-serializable request body. */
19
+ body?: unknown
20
+
21
+ /** Additional HTTP headers. */
22
+ headers?: RequestInit["headers"]
23
+
24
+ /** HTTP method. */
25
+ method?: string
26
+ }
27
+
28
+ /**
29
+ * Creates a small authenticated Microsoft Graph client for Teams APIs.
30
+ *
31
+ * The raw `fetch` method is an escape hatch for Graph operations not yet
32
+ * represented by a built-in action.
33
+ *
34
+ * @param secret - Refreshed Microsoft OAuth integration secret.
35
+ */
36
+ export function getTeamsGraphApi(secret: Record<string, unknown>) {
37
+ const { accessToken } = MICROSOFT_SECRET_SCHEMA.parse(secret)
38
+
39
+ /**
40
+ * Performs one authenticated Graph request.
41
+ *
42
+ * @param path - Relative or absolute Microsoft Graph URL.
43
+ * @param init - Standard fetch request options.
44
+ */
45
+ async function graphFetch(path: string, init?: RequestInit) {
46
+ const headers = new Headers(init?.headers)
47
+ headers.set("Accept", "application/json")
48
+ headers.set("Authorization", `Bearer ${accessToken}`)
49
+ return fetch(new URL(path.replace(/^\//, ""), GRAPH_BASE_URL), {
50
+ ...init,
51
+ headers,
52
+ })
53
+ }
54
+
55
+ /**
56
+ * Performs one authenticated Graph JSON request.
57
+ *
58
+ * @param path - Relative or absolute Microsoft Graph URL.
59
+ * @param options - HTTP method, body, and headers.
60
+ */
61
+ async function request(
62
+ path: string,
63
+ options: TeamsGraphRequestOptions = {},
64
+ ): Promise<unknown> {
65
+ const headers = new Headers(options.headers)
66
+ if (options.body !== undefined) {
67
+ headers.set("Content-Type", "application/json")
68
+ }
69
+ const response = await graphFetch(path, {
70
+ body:
71
+ options.body === undefined ? undefined : JSON.stringify(options.body),
72
+ headers,
73
+ method: options.method,
74
+ })
75
+
76
+ if (!response.ok) {
77
+ const payload = GRAPH_ERROR_SCHEMA.safeParse(
78
+ await response.json().catch(() => undefined),
79
+ )
80
+ const graphError = payload.success ? payload.data.error : undefined
81
+ const detail = [graphError?.code, graphError?.message]
82
+ .filter(Boolean)
83
+ .join(": ")
84
+ throw new Error(
85
+ `Microsoft Graph request failed with ${response.status} ${response.statusText}${detail ? `: ${detail}` : ""}.`,
86
+ )
87
+ }
88
+
89
+ if (response.status === 202 || response.status === 204) return undefined
90
+ return response.json()
91
+ }
92
+
93
+ return {
94
+ /** Performs an authenticated request and returns the raw Response. */
95
+ fetch: graphFetch,
96
+
97
+ /** Performs an authenticated request and returns its untrusted JSON value. */
98
+ request,
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Reads Graph collection pages until the requested limit is reached.
104
+ *
105
+ * @param request - Authenticated Graph JSON request function.
106
+ * @param path - Initial relative Graph path.
107
+ * @param itemSchema - Schema for one collection item.
108
+ * @param limit - Maximum total items.
109
+ */
110
+ export async function listTeamsGraphCollection<T>(
111
+ request: (path: string) => Promise<unknown>,
112
+ path: string,
113
+ itemSchema: z.ZodType<T>,
114
+ limit: number,
115
+ ) {
116
+ const pageSchema = z.object({
117
+ "@odata.nextLink": z.string().optional(),
118
+ value: itemSchema.array(),
119
+ })
120
+ const items: T[] = []
121
+ let nextPath: string | undefined = path
122
+
123
+ while (nextPath && items.length < limit) {
124
+ const page = pageSchema.parse(await request(nextPath))
125
+ items.push(...page.value)
126
+ nextPath = page["@odata.nextLink"]
127
+ }
128
+
129
+ return items.slice(0, limit)
130
+ }
@@ -0,0 +1,27 @@
1
+ import { z } from "zod"
2
+ import {
3
+ TEAMS_CHANNEL_MESSAGE_POSTED_EVENT_SCHEMA,
4
+ TEAMS_CHAT_MESSAGE_POSTED_EVENT_SCHEMA,
5
+ } from "./schemas"
6
+
7
+ export * from "./graph"
8
+ export * from "./schemas"
9
+
10
+ export const TEAMS_CHANNEL_TRIGGER_CONFIG_SCHEMA = z.object({
11
+ channel: z.string().trim().min(1),
12
+ team: z.string().trim().min(1),
13
+ })
14
+ export const TEAMS_CHAT_TRIGGER_CONFIG_SCHEMA = z.object({
15
+ chatId: z.string().min(1),
16
+ })
17
+
18
+ export const teamsTriggerContracts = {
19
+ "teams.channel.message.posted": {
20
+ configSchema: TEAMS_CHANNEL_TRIGGER_CONFIG_SCHEMA,
21
+ eventSchema: TEAMS_CHANNEL_MESSAGE_POSTED_EVENT_SCHEMA,
22
+ },
23
+ "teams.chat.message.posted": {
24
+ configSchema: TEAMS_CHAT_TRIGGER_CONFIG_SCHEMA,
25
+ eventSchema: TEAMS_CHAT_MESSAGE_POSTED_EVENT_SCHEMA,
26
+ },
27
+ } as const
@@ -0,0 +1,463 @@
1
+ import { z } from "zod"
2
+
3
+ const OPTIONAL_DATE_SCHEMA = z
4
+ .union([
5
+ z.date(),
6
+ z.iso.datetime({ offset: true }).transform((value) => new Date(value)),
7
+ ])
8
+ .nullish()
9
+ .transform((value) => value ?? undefined)
10
+ const OPTIONAL_STRING_SCHEMA = z
11
+ .string()
12
+ .nullish()
13
+ .transform((value) => value ?? undefined)
14
+
15
+ export const TEAMS_TEAM_SCHEMA = z.object({
16
+ /** Whether the team is archived. */
17
+ isArchived: z.boolean().prefault(false),
18
+
19
+ /** Team classification assigned by the organization. */
20
+ classification: OPTIONAL_STRING_SCHEMA,
21
+
22
+ /** Team description. */
23
+ description: OPTIONAL_STRING_SCHEMA,
24
+
25
+ /** Human-readable team name. */
26
+ displayName: z.string(),
27
+
28
+ /** Opaque Microsoft team identifier. */
29
+ teamId: z.string(),
30
+
31
+ /** Team specialization, when configured. */
32
+ specialization: OPTIONAL_STRING_SCHEMA,
33
+
34
+ /** Team visibility. */
35
+ visibility: z
36
+ .enum(["private", "public", "hiddenMembership", "unknownFutureValue"])
37
+ .nullish()
38
+ .transform((value) => value ?? undefined),
39
+
40
+ /** Microsoft Teams web URL. */
41
+ webUrl: OPTIONAL_STRING_SCHEMA,
42
+ })
43
+
44
+ export const GRAPH_TEAM_SCHEMA = z
45
+ .looseObject({
46
+ classification: z.string().nullish(),
47
+ description: z.string().nullish(),
48
+ displayName: z.string(),
49
+ id: z.string(),
50
+ isArchived: z.boolean().optional(),
51
+ specialization: z.string().nullish(),
52
+ visibility: z
53
+ .enum(["private", "public", "hiddenMembership", "unknownFutureValue"])
54
+ .nullish(),
55
+ webUrl: z.string().nullish(),
56
+ })
57
+ .transform((team) => TEAMS_TEAM_SCHEMA.parse({ ...team, teamId: team.id }))
58
+
59
+ export const TEAMS_CHANNEL_SCHEMA = z.object({
60
+ /** Time the channel was created. */
61
+ createdAt: OPTIONAL_DATE_SCHEMA,
62
+
63
+ /** Channel description. */
64
+ description: OPTIONAL_STRING_SCHEMA,
65
+
66
+ /** Human-readable channel name. */
67
+ displayName: z.string(),
68
+
69
+ /** Email address assigned to the channel. */
70
+ email: OPTIONAL_STRING_SCHEMA,
71
+
72
+ /** Opaque Microsoft channel identifier. */
73
+ channelId: z.string(),
74
+
75
+ /** Whether the channel is archived. */
76
+ isArchived: z.boolean().prefault(false),
77
+
78
+ /** Standard, private, or shared membership model. */
79
+ membershipType: z
80
+ .enum(["standard", "private", "shared", "unknownFutureValue"])
81
+ .nullish()
82
+ .transform((value) => value ?? undefined),
83
+
84
+ /** Microsoft Teams web URL. */
85
+ webUrl: OPTIONAL_STRING_SCHEMA,
86
+ })
87
+
88
+ export const GRAPH_CHANNEL_SCHEMA = z
89
+ .looseObject({
90
+ createdDateTime: z.string().nullish(),
91
+ description: z.string().nullish(),
92
+ displayName: z.string(),
93
+ email: z.string().nullish(),
94
+ id: z.string(),
95
+ isArchived: z.boolean().optional(),
96
+ membershipType: z
97
+ .enum(["standard", "private", "shared", "unknownFutureValue"])
98
+ .nullish(),
99
+ webUrl: z.string().nullish(),
100
+ })
101
+ .transform((channel) =>
102
+ TEAMS_CHANNEL_SCHEMA.parse({
103
+ ...channel,
104
+ channelId: channel.id,
105
+ createdAt: channel.createdDateTime,
106
+ }),
107
+ )
108
+
109
+ export const TEAMS_MEMBER_SCHEMA = z.object({
110
+ /** Member display name. */
111
+ displayName: OPTIONAL_STRING_SCHEMA,
112
+
113
+ /** Member email address, when Graph exposes it. */
114
+ email: OPTIONAL_STRING_SCHEMA,
115
+
116
+ /** Opaque conversation membership identifier. */
117
+ memberId: z.string(),
118
+
119
+ /** Membership roles such as `owner`. */
120
+ roles: z.string().array().prefault([]),
121
+
122
+ /** Microsoft Entra tenant identifier. */
123
+ tenantId: OPTIONAL_STRING_SCHEMA,
124
+
125
+ /** Microsoft Entra user identifier, when the member is a user. */
126
+ userId: OPTIONAL_STRING_SCHEMA,
127
+
128
+ /** Earliest history visible to this member. */
129
+ visibleHistoryStartAt: OPTIONAL_DATE_SCHEMA,
130
+ })
131
+
132
+ export const GRAPH_MEMBER_SCHEMA = z
133
+ .looseObject({
134
+ displayName: z.string().nullish(),
135
+ email: z.string().nullish(),
136
+ id: z.string(),
137
+ roles: z.string().array().optional(),
138
+ tenantId: z.string().nullish(),
139
+ userId: z.string().nullish(),
140
+ visibleHistoryStartDateTime: z.string().nullish(),
141
+ })
142
+ .transform((member) =>
143
+ TEAMS_MEMBER_SCHEMA.parse({
144
+ ...member,
145
+ memberId: member.id,
146
+ visibleHistoryStartAt: member.visibleHistoryStartDateTime,
147
+ }),
148
+ )
149
+
150
+ export const TEAMS_CHAT_SCHEMA = z.object({
151
+ /** Chat kind. */
152
+ chatType: z.enum(["oneOnOne", "group", "meeting", "unknownFutureValue"]),
153
+
154
+ /** Time the chat was created. */
155
+ createdAt: OPTIONAL_DATE_SCHEMA,
156
+
157
+ /** Opaque Microsoft chat identifier. */
158
+ chatId: z.string(),
159
+
160
+ /** Time the chat was last updated. */
161
+ updatedAt: OPTIONAL_DATE_SCHEMA,
162
+
163
+ /** Microsoft Entra tenant identifier. */
164
+ tenantId: OPTIONAL_STRING_SCHEMA,
165
+
166
+ /** Optional group-chat or meeting topic. */
167
+ topic: OPTIONAL_STRING_SCHEMA,
168
+
169
+ /** Microsoft Teams web URL. */
170
+ webUrl: OPTIONAL_STRING_SCHEMA,
171
+ })
172
+
173
+ export const GRAPH_CHAT_SCHEMA = z
174
+ .looseObject({
175
+ chatType: z.enum(["oneOnOne", "group", "meeting", "unknownFutureValue"]),
176
+ createdDateTime: z.string().nullish(),
177
+ id: z.string(),
178
+ lastUpdatedDateTime: z.string().nullish(),
179
+ tenantId: z.string().nullish(),
180
+ topic: z.string().nullish(),
181
+ webUrl: z.string().nullish(),
182
+ })
183
+ .transform((chat) =>
184
+ TEAMS_CHAT_SCHEMA.parse({
185
+ ...chat,
186
+ chatId: chat.id,
187
+ createdAt: chat.createdDateTime,
188
+ updatedAt: chat.lastUpdatedDateTime,
189
+ }),
190
+ )
191
+
192
+ export const TEAMS_MESSAGE_BODY_SCHEMA = z.object({
193
+ /** Message content. */
194
+ content: z.string(),
195
+
196
+ /** Plain text or HTML content type. */
197
+ contentType: z.enum(["text", "html"]),
198
+ })
199
+
200
+ const TEAMS_MESSAGE_FROM_SCHEMA = z.object({
201
+ /** Application identifier, when sent by an app. */
202
+ applicationId: OPTIONAL_STRING_SCHEMA,
203
+
204
+ /** Device identifier, when sent by a device. */
205
+ deviceId: OPTIONAL_STRING_SCHEMA,
206
+
207
+ /** Display name supplied by Teams. */
208
+ displayName: OPTIONAL_STRING_SCHEMA,
209
+
210
+ /** Microsoft Entra user identifier, when sent by a user. */
211
+ userId: OPTIONAL_STRING_SCHEMA,
212
+ })
213
+
214
+ const TEAMS_MESSAGE_ATTACHMENT_SCHEMA = z.object({
215
+ /** Provider attachment identifier. */
216
+ attachmentId: z.string(),
217
+
218
+ /** Attachment content or card JSON. */
219
+ content: OPTIONAL_STRING_SCHEMA,
220
+
221
+ /** MIME media type or Teams card type. */
222
+ contentType: z.string(),
223
+
224
+ /** Display name. */
225
+ name: OPTIONAL_STRING_SCHEMA,
226
+
227
+ /** External content URL. */
228
+ contentUrl: OPTIONAL_STRING_SCHEMA,
229
+ })
230
+
231
+ const TEAMS_MESSAGE_MENTION_SCHEMA = z.object({
232
+ /** Mention identifier corresponding to the HTML `<at>` token. */
233
+ mentionId: z.number().int(),
234
+
235
+ /** Text displayed for the mention. */
236
+ mentionText: z.string(),
237
+
238
+ /** Mentioned conversation identity. */
239
+ mentioned: TEAMS_MESSAGE_FROM_SCHEMA,
240
+ })
241
+
242
+ const TEAMS_MESSAGE_REACTION_SCHEMA = z.object({
243
+ /** Reaction name such as `like` or `heart`. */
244
+ reactionType: z.string(),
245
+
246
+ /** Time the reaction was created. */
247
+ createdAt: OPTIONAL_DATE_SCHEMA,
248
+
249
+ /** Identity that created the reaction. */
250
+ user: TEAMS_MESSAGE_FROM_SCHEMA,
251
+ })
252
+
253
+ export const TEAMS_CHAT_MESSAGE_SCHEMA = z.object({
254
+ /** Attachments and cards associated with the message. */
255
+ attachments: TEAMS_MESSAGE_ATTACHMENT_SCHEMA.array().prefault([]),
256
+
257
+ /** Message body. */
258
+ body: TEAMS_MESSAGE_BODY_SCHEMA,
259
+
260
+ /** Time the message was created. */
261
+ createdAt: OPTIONAL_DATE_SCHEMA,
262
+
263
+ /** Time the message was soft-deleted. */
264
+ deletedAt: OPTIONAL_DATE_SCHEMA,
265
+
266
+ /** Graph concurrency token. */
267
+ etag: OPTIONAL_STRING_SCHEMA,
268
+
269
+ /** Sender identity. */
270
+ from: TEAMS_MESSAGE_FROM_SCHEMA.nullish().transform(
271
+ (value) => value ?? undefined,
272
+ ),
273
+
274
+ /** Message importance. */
275
+ importance: z
276
+ .enum(["normal", "high", "urgent", "unknownFutureValue"])
277
+ .prefault("normal"),
278
+
279
+ /** Message locale. */
280
+ locale: OPTIONAL_STRING_SCHEMA,
281
+
282
+ /** Opaque Teams message identifier. */
283
+ messageId: z.string(),
284
+
285
+ /** Message kind. */
286
+ messageType: z.string(),
287
+
288
+ /** Structured mentions embedded in the body. */
289
+ mentions: TEAMS_MESSAGE_MENTION_SCHEMA.array().prefault([]),
290
+
291
+ /** Reactions currently applied to the message. */
292
+ reactions: TEAMS_MESSAGE_REACTION_SCHEMA.array().prefault([]),
293
+
294
+ /** Parent channel message identifier for a reply. */
295
+ replyToId: OPTIONAL_STRING_SCHEMA,
296
+
297
+ /** Subject, commonly present on channel announcements. */
298
+ subject: OPTIONAL_STRING_SCHEMA,
299
+
300
+ /** Provider-generated summary. */
301
+ summary: OPTIONAL_STRING_SCHEMA,
302
+
303
+ /** Time the message was last modified. */
304
+ updatedAt: OPTIONAL_DATE_SCHEMA,
305
+
306
+ /** Microsoft Teams web URL. */
307
+ webUrl: OPTIONAL_STRING_SCHEMA,
308
+ })
309
+
310
+ const GRAPH_IDENTITY_SCHEMA = z
311
+ .looseObject({
312
+ id: z.string().nullish(),
313
+ displayName: z.string().nullish(),
314
+ })
315
+ .optional()
316
+
317
+ export const GRAPH_CHAT_MESSAGE_SCHEMA = z
318
+ .looseObject({
319
+ attachments: z
320
+ .looseObject({
321
+ content: z.string().nullish(),
322
+ contentType: z.string(),
323
+ contentUrl: z.string().nullish(),
324
+ id: z.string(),
325
+ name: z.string().nullish(),
326
+ })
327
+ .array()
328
+ .optional(),
329
+ body: z.object({
330
+ content: z.string(),
331
+ contentType: z.enum(["text", "html"]),
332
+ }),
333
+ createdDateTime: z.string().nullish(),
334
+ deletedDateTime: z.string().nullish(),
335
+ etag: z.string().nullish(),
336
+ from: z
337
+ .looseObject({
338
+ application: GRAPH_IDENTITY_SCHEMA,
339
+ device: GRAPH_IDENTITY_SCHEMA,
340
+ user: GRAPH_IDENTITY_SCHEMA,
341
+ })
342
+ .nullish(),
343
+ id: z.string(),
344
+ importance: z
345
+ .enum(["normal", "high", "urgent", "unknownFutureValue"])
346
+ .optional(),
347
+ lastModifiedDateTime: z.string().nullish(),
348
+ locale: z.string().nullish(),
349
+ mentions: z
350
+ .looseObject({
351
+ id: z.number().int(),
352
+ mentionText: z.string(),
353
+ mentioned: z.looseObject({
354
+ application: GRAPH_IDENTITY_SCHEMA,
355
+ device: GRAPH_IDENTITY_SCHEMA,
356
+ user: GRAPH_IDENTITY_SCHEMA,
357
+ }),
358
+ })
359
+ .array()
360
+ .optional(),
361
+ messageType: z.string(),
362
+ reactions: z
363
+ .looseObject({
364
+ createdDateTime: z.string().nullish(),
365
+ reactionType: z.string(),
366
+ user: z.looseObject({
367
+ application: GRAPH_IDENTITY_SCHEMA,
368
+ device: GRAPH_IDENTITY_SCHEMA,
369
+ user: GRAPH_IDENTITY_SCHEMA,
370
+ }),
371
+ })
372
+ .array()
373
+ .optional(),
374
+ replyToId: z.string().nullish(),
375
+ subject: z.string().nullish(),
376
+ summary: z.string().nullish(),
377
+ webUrl: z.string().nullish(),
378
+ })
379
+ .transform((message) =>
380
+ TEAMS_CHAT_MESSAGE_SCHEMA.parse({
381
+ attachments: message.attachments?.map((attachment) => ({
382
+ attachmentId: attachment.id,
383
+ content: attachment.content,
384
+ contentType: attachment.contentType,
385
+ contentUrl: attachment.contentUrl,
386
+ name: attachment.name,
387
+ })),
388
+ body: message.body,
389
+ createdAt: message.createdDateTime,
390
+ deletedAt: message.deletedDateTime,
391
+ etag: message.etag,
392
+ from: graphIdentitySet(message.from),
393
+ importance: message.importance,
394
+ locale: message.locale,
395
+ mentions: message.mentions?.map((mention) => ({
396
+ mentionId: mention.id,
397
+ mentioned: graphIdentitySet(mention.mentioned),
398
+ mentionText: mention.mentionText,
399
+ })),
400
+ messageId: message.id,
401
+ messageType: message.messageType,
402
+ reactions: message.reactions?.map((reaction) => ({
403
+ createdAt: reaction.createdDateTime,
404
+ reactionType: reaction.reactionType,
405
+ user: graphIdentitySet(reaction.user),
406
+ })),
407
+ replyToId: message.replyToId,
408
+ subject: message.subject,
409
+ summary: message.summary,
410
+ updatedAt: message.lastModifiedDateTime,
411
+ webUrl: message.webUrl,
412
+ }),
413
+ )
414
+
415
+ /**
416
+ * Normalizes an untrusted Microsoft Graph chat-message payload.
417
+ *
418
+ * @param payload - Provider chat-message payload.
419
+ */
420
+ export function normalizeTeamsChatMessage(payload: unknown) {
421
+ return GRAPH_CHAT_MESSAGE_SCHEMA.parse(payload)
422
+ }
423
+
424
+ export const TEAMS_CHANNEL_MESSAGE_POSTED_EVENT_SCHEMA =
425
+ TEAMS_CHAT_MESSAGE_SCHEMA.extend({
426
+ /** Channel containing the posted message. */
427
+ channelId: z.string(),
428
+
429
+ /** Team containing the posted message. */
430
+ teamId: z.string(),
431
+ })
432
+
433
+ export const TEAMS_CHAT_MESSAGE_POSTED_EVENT_SCHEMA =
434
+ TEAMS_CHAT_MESSAGE_SCHEMA.extend({
435
+ /** Chat containing the posted message. */
436
+ chatId: z.string(),
437
+ })
438
+
439
+ /**
440
+ * Flattens Graph's user/application/device identity-set union.
441
+ *
442
+ * @param identitySet - Provider identity set.
443
+ */
444
+ function graphIdentitySet(
445
+ identitySet:
446
+ | {
447
+ application?: { displayName?: string | null; id?: string | null }
448
+ device?: { displayName?: string | null; id?: string | null }
449
+ user?: { displayName?: string | null; id?: string | null }
450
+ }
451
+ | null
452
+ | undefined,
453
+ ) {
454
+ return {
455
+ applicationId: identitySet?.application?.id,
456
+ deviceId: identitySet?.device?.id,
457
+ displayName:
458
+ identitySet?.user?.displayName ??
459
+ identitySet?.application?.displayName ??
460
+ identitySet?.device?.displayName,
461
+ userId: identitySet?.user?.id,
462
+ }
463
+ }