@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,326 @@
1
+ import { z } from "zod";
2
+ const WHATSAPP_ERROR_SCHEMA = z.object({
3
+ code: z.number().int(),
4
+ error_data: z
5
+ .object({
6
+ details: z.string().optional(),
7
+ messaging_product: z.string().optional(),
8
+ })
9
+ .optional(),
10
+ error_subcode: z.number().int().optional(),
11
+ fbtrace_id: z.string().optional(),
12
+ message: z.string(),
13
+ title: z.string().optional(),
14
+ });
15
+ const WHATSAPP_MESSAGE_SCHEMA = z.object({
16
+ audio: z
17
+ .object({ id: z.string(), mime_type: z.string().optional() })
18
+ .optional(),
19
+ button: z.object({ payload: z.string(), text: z.string() }).optional(),
20
+ contacts: z.json().array().optional(),
21
+ context: z
22
+ .object({
23
+ forwarded: z.boolean().optional(),
24
+ from: z.string().optional(),
25
+ id: z.string(),
26
+ })
27
+ .optional(),
28
+ document: z
29
+ .object({
30
+ caption: z.string().optional(),
31
+ filename: z.string().optional(),
32
+ id: z.string(),
33
+ mime_type: z.string().optional(),
34
+ })
35
+ .optional(),
36
+ errors: WHATSAPP_ERROR_SCHEMA.array().optional(),
37
+ from: z.string(),
38
+ id: z.string(),
39
+ image: z
40
+ .object({
41
+ caption: z.string().optional(),
42
+ id: z.string(),
43
+ mime_type: z.string().optional(),
44
+ })
45
+ .optional(),
46
+ interactive: z
47
+ .object({
48
+ button_reply: z.object({ id: z.string(), title: z.string() }).optional(),
49
+ list_reply: z
50
+ .object({
51
+ description: z.string().optional(),
52
+ id: z.string(),
53
+ title: z.string(),
54
+ })
55
+ .optional(),
56
+ type: z.enum(["button_reply", "list_reply"]),
57
+ })
58
+ .optional(),
59
+ location: z
60
+ .object({
61
+ address: z.string().optional(),
62
+ latitude: z.number(),
63
+ longitude: z.number(),
64
+ name: z.string().optional(),
65
+ url: z.string().optional(),
66
+ })
67
+ .optional(),
68
+ order: z.json().optional(),
69
+ reaction: z.object({ emoji: z.string(), message_id: z.string() }).optional(),
70
+ referral: z.json().optional(),
71
+ sticker: z
72
+ .object({ id: z.string(), mime_type: z.string().optional() })
73
+ .optional(),
74
+ system: z.json().optional(),
75
+ text: z.object({ body: z.string() }).optional(),
76
+ timestamp: z.string(),
77
+ type: z.enum([
78
+ "audio",
79
+ "button",
80
+ "contacts",
81
+ "document",
82
+ "image",
83
+ "interactive",
84
+ "location",
85
+ "order",
86
+ "reaction",
87
+ "sticker",
88
+ "system",
89
+ "text",
90
+ "unknown",
91
+ "unsupported",
92
+ "video",
93
+ ]),
94
+ unknown: z.json().optional(),
95
+ unsupported: z.json().optional(),
96
+ video: z
97
+ .object({
98
+ caption: z.string().optional(),
99
+ id: z.string(),
100
+ mime_type: z.string().optional(),
101
+ })
102
+ .optional(),
103
+ });
104
+ const WHATSAPP_STATUS_SCHEMA = z.object({
105
+ biz_opaque_callback_data: z.string().optional(),
106
+ conversation: z
107
+ .object({
108
+ expiration_timestamp: z.string().optional(),
109
+ id: z.string(),
110
+ origin: z.object({ type: z.string() }),
111
+ })
112
+ .optional(),
113
+ errors: WHATSAPP_ERROR_SCHEMA.array().optional(),
114
+ id: z.string(),
115
+ pricing: z
116
+ .object({
117
+ billable: z.boolean().optional(),
118
+ category: z.string(),
119
+ pricing_model: z.enum(["CBP", "PMP"]),
120
+ type: z
121
+ .enum(["regular", "free_customer_service", "free_entry_point"])
122
+ .optional(),
123
+ })
124
+ .optional(),
125
+ recipient_id: z.string(),
126
+ status: z.enum(["sent", "delivered", "read", "failed", "played"]),
127
+ timestamp: z.string(),
128
+ });
129
+ const WHATSAPP_NORMALIZED_ERROR_SCHEMA = z.object({
130
+ code: z.number().int(),
131
+ details: z.string().optional(),
132
+ message: z.string(),
133
+ subcode: z.number().int().optional(),
134
+ title: z.string().optional(),
135
+ traceId: z.string().optional(),
136
+ });
137
+ const WHATSAPP_CHANGE_VALUE_SCHEMA = z.object({
138
+ contacts: z
139
+ .object({
140
+ profile: z.object({ name: z.string().optional() }),
141
+ wa_id: z.string(),
142
+ })
143
+ .array()
144
+ .optional(),
145
+ messages: WHATSAPP_MESSAGE_SCHEMA.array().optional(),
146
+ messaging_product: z.literal("whatsapp"),
147
+ metadata: z.object({
148
+ display_phone_number: z.string(),
149
+ phone_number_id: z.string(),
150
+ }),
151
+ statuses: WHATSAPP_STATUS_SCHEMA.array().optional(),
152
+ });
153
+ /** Provider-native WhatsApp webhook envelope. */
154
+ export const WHATSAPP_WEBHOOK_SCHEMA = z.object({
155
+ entry: z
156
+ .object({
157
+ changes: z
158
+ .object({
159
+ field: z.literal("messages"),
160
+ value: WHATSAPP_CHANGE_VALUE_SCHEMA,
161
+ })
162
+ .array(),
163
+ id: z.string(),
164
+ })
165
+ .array(),
166
+ object: z.literal("whatsapp_business_account"),
167
+ });
168
+ /** Normalized incoming WhatsApp message event. */
169
+ export const WHATSAPP_MESSAGE_RECEIVED_EVENT_SCHEMA = z.object({
170
+ businessAccountId: z.string(),
171
+ displayPhoneNumber: z.string(),
172
+ message: z.object({
173
+ content: z.json().optional(),
174
+ context: z
175
+ .object({
176
+ forwarded: z.boolean().optional(),
177
+ from: z.string().optional(),
178
+ messageId: z.string(),
179
+ })
180
+ .optional(),
181
+ id: z.string(),
182
+ timestamp: z.string(),
183
+ type: WHATSAPP_MESSAGE_SCHEMA.shape.type,
184
+ }),
185
+ phoneNumberId: z.string(),
186
+ providerEvent: WHATSAPP_MESSAGE_SCHEMA,
187
+ sender: z.object({ id: z.string(), name: z.string().optional() }),
188
+ });
189
+ /** Normalized WhatsApp message status event. */
190
+ export const WHATSAPP_MESSAGE_STATUS_EVENT_SCHEMA = z.object({
191
+ businessAccountId: z.string(),
192
+ callbackData: z.string().optional(),
193
+ conversation: z
194
+ .object({
195
+ expirationTimestamp: z.string().optional(),
196
+ id: z.string(),
197
+ originType: z.string(),
198
+ })
199
+ .optional(),
200
+ errors: WHATSAPP_NORMALIZED_ERROR_SCHEMA.array().optional(),
201
+ messageId: z.string(),
202
+ phoneNumberId: z.string(),
203
+ pricing: z
204
+ .object({
205
+ billable: z.boolean().optional(),
206
+ category: z.string(),
207
+ model: z.enum(["CBP", "PMP"]),
208
+ type: z
209
+ .enum(["regular", "free_customer_service", "free_entry_point"])
210
+ .optional(),
211
+ })
212
+ .optional(),
213
+ providerEvent: WHATSAPP_STATUS_SCHEMA,
214
+ recipientId: z.string(),
215
+ status: WHATSAPP_STATUS_SCHEMA.shape.status,
216
+ timestamp: z.string(),
217
+ });
218
+ export const WHATSAPP_MESSAGE_SENT_EVENT_SCHEMA = WHATSAPP_MESSAGE_STATUS_EVENT_SCHEMA.extend({
219
+ providerEvent: WHATSAPP_STATUS_SCHEMA.extend({ status: z.literal("sent") }),
220
+ status: z.literal("sent"),
221
+ });
222
+ export const WHATSAPP_MESSAGE_DELIVERED_EVENT_SCHEMA = WHATSAPP_MESSAGE_STATUS_EVENT_SCHEMA.extend({
223
+ providerEvent: WHATSAPP_STATUS_SCHEMA.extend({
224
+ status: z.literal("delivered"),
225
+ }),
226
+ status: z.literal("delivered"),
227
+ });
228
+ export const WHATSAPP_MESSAGE_READ_EVENT_SCHEMA = WHATSAPP_MESSAGE_STATUS_EVENT_SCHEMA.extend({
229
+ providerEvent: WHATSAPP_STATUS_SCHEMA.extend({ status: z.literal("read") }),
230
+ status: z.literal("read"),
231
+ });
232
+ export const WHATSAPP_MESSAGE_FAILED_EVENT_SCHEMA = WHATSAPP_MESSAGE_STATUS_EVENT_SCHEMA.extend({
233
+ providerEvent: WHATSAPP_STATUS_SCHEMA.extend({
234
+ status: z.literal("failed"),
235
+ }),
236
+ status: z.literal("failed"),
237
+ });
238
+ export const WHATSAPP_MESSAGE_PLAYED_EVENT_SCHEMA = WHATSAPP_MESSAGE_STATUS_EVENT_SCHEMA.extend({
239
+ providerEvent: WHATSAPP_STATUS_SCHEMA.extend({
240
+ status: z.literal("played"),
241
+ }),
242
+ status: z.literal("played"),
243
+ });
244
+ /**
245
+ * Flattens one verified provider callback into independently ingestible events.
246
+ *
247
+ * @param input - Untrusted WhatsApp webhook envelope.
248
+ */
249
+ export function normalizeWhatsAppWebhook(input) {
250
+ // Parse once before flattening every entry and change in the delivery batch.
251
+ const webhook = WHATSAPP_WEBHOOK_SCHEMA.parse(input);
252
+ const messages = [];
253
+ const statuses = [];
254
+ for (const entry of webhook.entry) {
255
+ for (const { value } of entry.changes) {
256
+ for (const message of value.messages ?? []) {
257
+ // Meta supplies contacts separately, so match the sender for its profile.
258
+ const sender = value.contacts?.find(({ wa_id }) => wa_id === message.from);
259
+ messages.push({
260
+ businessAccountId: entry.id,
261
+ displayPhoneNumber: value.metadata.display_phone_number,
262
+ message: {
263
+ content: message[message.type],
264
+ ...(message.context && {
265
+ context: {
266
+ forwarded: message.context.forwarded,
267
+ from: message.context.from,
268
+ messageId: message.context.id,
269
+ },
270
+ }),
271
+ id: message.id,
272
+ timestamp: message.timestamp,
273
+ type: message.type,
274
+ },
275
+ phoneNumberId: value.metadata.phone_number_id,
276
+ providerEvent: message,
277
+ sender: { id: message.from, name: sender?.profile.name },
278
+ });
279
+ }
280
+ for (const status of value.statuses ?? []) {
281
+ statuses.push({
282
+ businessAccountId: entry.id,
283
+ callbackData: status.biz_opaque_callback_data,
284
+ ...(status.conversation && {
285
+ conversation: {
286
+ expirationTimestamp: status.conversation.expiration_timestamp,
287
+ id: status.conversation.id,
288
+ originType: status.conversation.origin.type,
289
+ },
290
+ }),
291
+ errors: status.errors?.map(normalizeWhatsAppError),
292
+ messageId: status.id,
293
+ phoneNumberId: value.metadata.phone_number_id,
294
+ ...(status.pricing && {
295
+ pricing: {
296
+ billable: status.pricing.billable,
297
+ category: status.pricing.category,
298
+ model: status.pricing.pricing_model,
299
+ type: status.pricing.type,
300
+ },
301
+ }),
302
+ providerEvent: status,
303
+ recipientId: status.recipient_id,
304
+ status: status.status,
305
+ timestamp: status.timestamp,
306
+ });
307
+ }
308
+ }
309
+ }
310
+ return { messages, statuses };
311
+ }
312
+ /**
313
+ * Converts one provider-native Meta error to the public event shape.
314
+ *
315
+ * @param error - Provider-native webhook error.
316
+ */
317
+ function normalizeWhatsAppError(error) {
318
+ return {
319
+ code: error.code,
320
+ details: error.error_data?.details,
321
+ message: error.message,
322
+ subcode: error.error_subcode,
323
+ title: error.title,
324
+ traceId: error.fbtrace_id,
325
+ };
326
+ }
package/package.json ADDED
@@ -0,0 +1,169 @@
1
+ {
2
+ "name": "@automate.ax/integration-contracts",
3
+ "version": "0.55.0",
4
+ "description": "Shared integration payload contracts and provider primitives for Automate.ax.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/zachsents/automate.ax.git",
9
+ "directory": "packages/integration-contracts"
10
+ },
11
+ "homepage": "https://automate.ax",
12
+ "bugs": {
13
+ "url": "https://github.com/zachsents/automate.ax/issues"
14
+ },
15
+ "type": "module",
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "zshy": {
20
+ "exports": {
21
+ "./airtable": "./src/airtable/index.ts",
22
+ "./asana": "./src/asana/index.ts",
23
+ "./brevo": "./src/brevo/index.ts",
24
+ "./gmail": "./src/gmail/index.ts",
25
+ "./google-calendar": "./src/google-calendar/index.ts",
26
+ "./google-forms": "./src/google-forms/index.ts",
27
+ "./github": "./src/github/index.ts",
28
+ "./linear": "./src/linear/index.ts",
29
+ "./outlook": "./src/outlook/index.ts",
30
+ "./resend": "./src/resend/index.ts",
31
+ "./slack": "./src/slack/index.ts",
32
+ "./teams": "./src/teams/index.ts",
33
+ "./trello": "./src/trello/index.ts",
34
+ "./triggers": "./src/triggers.ts",
35
+ "./vercel": "./src/vercel/index.ts",
36
+ "./whatsapp": "./src/whatsapp/index.ts"
37
+ },
38
+ "cjs": false,
39
+ "conditions": {
40
+ "bun": "src"
41
+ }
42
+ },
43
+ "dependencies": {
44
+ "@automate.ax/codec": "0.55.0",
45
+ "@googleapis/calendar": "^15.0.0",
46
+ "@googleapis/forms": "^6.0.1",
47
+ "@googleapis/gmail": "^12.0.0",
48
+ "@octokit/openapi-webhooks-types": "^12.1.0",
49
+ "@octokit/rest": "^22.0.1",
50
+ "html-to-text": "^10.0.0",
51
+ "nodemailer": "^9.0.3",
52
+ "postal-mime": "^2.7.5",
53
+ "type-fest": "^5.6.0",
54
+ "zod": "^4.3.6"
55
+ },
56
+ "devDependencies": {
57
+ "@internal/config": "0.0.0",
58
+ "@types/bun": "latest",
59
+ "@types/html-to-text": "^9.0.4",
60
+ "@types/nodemailer": "^8.0.1",
61
+ "@typescript/native": "npm:typescript@^7.0.2",
62
+ "@zachsents/oxlint-config": "^0.4.1",
63
+ "concurrently": "^10.0.4",
64
+ "eslint": "^9.39.5",
65
+ "oxlint": "^1.76.0",
66
+ "oxlint-tsgolint": "^7.0.2001",
67
+ "zshy": "^0.7.2"
68
+ },
69
+ "scripts": {
70
+ "typecheck": "tsc --noEmit",
71
+ "lint": "concurrently --success all --kill-others-on-fail \"oxlint --type-aware\" \"bun --bun eslint .\"",
72
+ "lint:fix": "concurrently --success all --kill-others-on-fail \"oxlint --type-aware --fix --fix-suggestions\" \"bun --bun eslint . --fix\"",
73
+ "check": "bun run typecheck && bun run lint",
74
+ "build": "zshy",
75
+ "prepublishOnly": "bun run check && bun run build"
76
+ },
77
+ "files": [
78
+ "dist",
79
+ "src"
80
+ ],
81
+ "main": "./dist/index.js",
82
+ "module": "./dist/index.js",
83
+ "types": "./dist/index.d.ts",
84
+ "engines": {
85
+ "node": ">=24"
86
+ },
87
+ "exports": {
88
+ "./airtable": {
89
+ "bun": "./src/airtable/index.ts",
90
+ "types": "./dist/airtable/index.d.ts",
91
+ "default": "./dist/airtable/index.js"
92
+ },
93
+ "./asana": {
94
+ "bun": "./src/asana/index.ts",
95
+ "types": "./dist/asana/index.d.ts",
96
+ "default": "./dist/asana/index.js"
97
+ },
98
+ "./brevo": {
99
+ "bun": "./src/brevo/index.ts",
100
+ "types": "./dist/brevo/index.d.ts",
101
+ "default": "./dist/brevo/index.js"
102
+ },
103
+ "./gmail": {
104
+ "bun": "./src/gmail/index.ts",
105
+ "types": "./dist/gmail/index.d.ts",
106
+ "default": "./dist/gmail/index.js"
107
+ },
108
+ "./google-calendar": {
109
+ "bun": "./src/google-calendar/index.ts",
110
+ "types": "./dist/google-calendar/index.d.ts",
111
+ "default": "./dist/google-calendar/index.js"
112
+ },
113
+ "./google-forms": {
114
+ "bun": "./src/google-forms/index.ts",
115
+ "types": "./dist/google-forms/index.d.ts",
116
+ "default": "./dist/google-forms/index.js"
117
+ },
118
+ "./github": {
119
+ "bun": "./src/github/index.ts",
120
+ "types": "./dist/github/index.d.ts",
121
+ "default": "./dist/github/index.js"
122
+ },
123
+ "./linear": {
124
+ "bun": "./src/linear/index.ts",
125
+ "types": "./dist/linear/index.d.ts",
126
+ "default": "./dist/linear/index.js"
127
+ },
128
+ "./outlook": {
129
+ "bun": "./src/outlook/index.ts",
130
+ "types": "./dist/outlook/index.d.ts",
131
+ "default": "./dist/outlook/index.js"
132
+ },
133
+ "./resend": {
134
+ "bun": "./src/resend/index.ts",
135
+ "types": "./dist/resend/index.d.ts",
136
+ "default": "./dist/resend/index.js"
137
+ },
138
+ "./slack": {
139
+ "bun": "./src/slack/index.ts",
140
+ "types": "./dist/slack/index.d.ts",
141
+ "default": "./dist/slack/index.js"
142
+ },
143
+ "./teams": {
144
+ "bun": "./src/teams/index.ts",
145
+ "types": "./dist/teams/index.d.ts",
146
+ "default": "./dist/teams/index.js"
147
+ },
148
+ "./trello": {
149
+ "bun": "./src/trello/index.ts",
150
+ "types": "./dist/trello/index.d.ts",
151
+ "default": "./dist/trello/index.js"
152
+ },
153
+ "./triggers": {
154
+ "bun": "./src/triggers.ts",
155
+ "types": "./dist/triggers.d.ts",
156
+ "default": "./dist/triggers.js"
157
+ },
158
+ "./vercel": {
159
+ "bun": "./src/vercel/index.ts",
160
+ "types": "./dist/vercel/index.d.ts",
161
+ "default": "./dist/vercel/index.js"
162
+ },
163
+ "./whatsapp": {
164
+ "bun": "./src/whatsapp/index.ts",
165
+ "types": "./dist/whatsapp/index.d.ts",
166
+ "default": "./dist/whatsapp/index.js"
167
+ }
168
+ }
169
+ }
@@ -0,0 +1,66 @@
1
+ import { z } from "zod"
2
+
3
+ export const AIRTABLE_API_ORIGIN = "https://api.airtable.com/v0/"
4
+
5
+ const AIRTABLE_SECRET_SCHEMA = z.object({
6
+ accessToken: z.string().min(1),
7
+ })
8
+ const AIRTABLE_ERROR_SCHEMA = z.object({
9
+ error: z.union([
10
+ z.string(),
11
+ z.object({
12
+ message: z.string().optional(),
13
+ type: z.string().optional(),
14
+ }),
15
+ ]),
16
+ })
17
+
18
+ /** Authenticated raw Airtable Web API client for custom actions. */
19
+ export interface AirtableApi {
20
+ /**
21
+ * Sends a request relative to `https://api.airtable.com/v0/`.
22
+ *
23
+ * Non-successful responses throw with Airtable's provider error message.
24
+ *
25
+ * @param path - API path relative to the v0 root.
26
+ * @param init - Standard Fetch request options.
27
+ */
28
+ request(path: string, init?: RequestInit): Promise<Response>
29
+ }
30
+
31
+ /**
32
+ * Creates an authenticated raw Airtable Web API client.
33
+ *
34
+ * @param secret - Refreshed Airtable integration secret.
35
+ */
36
+ export function getAirtableApi(secret: Record<string, unknown>): AirtableApi {
37
+ const { accessToken } = AIRTABLE_SECRET_SCHEMA.parse(secret)
38
+
39
+ return {
40
+ request: async (path, init) => {
41
+ const headers = new Headers(init?.headers)
42
+ headers.set("Authorization", `Bearer ${accessToken}`)
43
+ if (init?.body !== undefined && !headers.has("Content-Type")) {
44
+ headers.set("Content-Type", "application/json")
45
+ }
46
+
47
+ const response = await fetch(new URL(path, AIRTABLE_API_ORIGIN), {
48
+ ...init,
49
+ headers,
50
+ })
51
+ if (!response.ok) {
52
+ const result = AIRTABLE_ERROR_SCHEMA.safeParse(
53
+ await response.json().catch(() => undefined),
54
+ )
55
+ const providerError = result.success ? result.data.error : undefined
56
+ throw new Error(
57
+ (typeof providerError === "string"
58
+ ? providerError
59
+ : (providerError?.message ?? providerError?.type)) ??
60
+ `Airtable request failed with status ${response.status}.`,
61
+ )
62
+ }
63
+ return response
64
+ },
65
+ }
66
+ }
@@ -0,0 +1,41 @@
1
+ import { z } from "zod"
2
+ import {
3
+ AIRTABLE_RECORD_CREATED_EVENT_SCHEMA,
4
+ AIRTABLE_RECORD_DELETED_EVENT_SCHEMA,
5
+ AIRTABLE_RECORD_MOVED_INTO_VIEW_EVENT_SCHEMA,
6
+ AIRTABLE_RECORD_MOVED_OUT_OF_VIEW_EVENT_SCHEMA,
7
+ AIRTABLE_RECORD_UPDATED_EVENT_SCHEMA,
8
+ } from "./schemas"
9
+
10
+ export * from "./api"
11
+ export * from "./schemas"
12
+
13
+ /** Canonical Airtable webhook scope shared by authoring and ingestion. */
14
+ export const AIRTABLE_TRIGGER_CONFIG_SCHEMA = z.object({
15
+ baseId: z.string(),
16
+ scopeId: z.string(),
17
+ scopeType: z.enum(["table", "view"]),
18
+ })
19
+
20
+ export const airtableTriggerContracts = {
21
+ "airtable.record.created": {
22
+ configSchema: AIRTABLE_TRIGGER_CONFIG_SCHEMA,
23
+ eventSchema: AIRTABLE_RECORD_CREATED_EVENT_SCHEMA,
24
+ },
25
+ "airtable.record.deleted": {
26
+ configSchema: AIRTABLE_TRIGGER_CONFIG_SCHEMA,
27
+ eventSchema: AIRTABLE_RECORD_DELETED_EVENT_SCHEMA,
28
+ },
29
+ "airtable.record.movedIntoView": {
30
+ configSchema: AIRTABLE_TRIGGER_CONFIG_SCHEMA,
31
+ eventSchema: AIRTABLE_RECORD_MOVED_INTO_VIEW_EVENT_SCHEMA,
32
+ },
33
+ "airtable.record.movedOutOfView": {
34
+ configSchema: AIRTABLE_TRIGGER_CONFIG_SCHEMA,
35
+ eventSchema: AIRTABLE_RECORD_MOVED_OUT_OF_VIEW_EVENT_SCHEMA,
36
+ },
37
+ "airtable.record.updated": {
38
+ configSchema: AIRTABLE_TRIGGER_CONFIG_SCHEMA,
39
+ eventSchema: AIRTABLE_RECORD_UPDATED_EVENT_SCHEMA,
40
+ },
41
+ } as const