@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,231 @@
1
+ import { z } from "zod"
2
+
3
+ const AIRTABLE_FIELDS_BY_ID_SCHEMA = z.record(z.string(), z.json())
4
+ const AIRTABLE_ACTION_METADATA_SCHEMA = z
5
+ .looseObject({
6
+ /** Airtable system that caused the transaction. */
7
+ source: z.string(),
8
+
9
+ /** Provider-specific actor or source details. */
10
+ sourceMetadata: z.record(z.string(), z.json()).optional(),
11
+ })
12
+ .catchall(z.json())
13
+ const AIRTABLE_CREATED_RECORD_SCHEMA = z.looseObject({
14
+ cellValuesByFieldId: AIRTABLE_FIELDS_BY_ID_SCHEMA,
15
+ createdTime: z.iso.datetime({ offset: true }),
16
+ })
17
+ const AIRTABLE_CHANGED_RECORD_SCHEMA = z.looseObject({
18
+ current: z.looseObject({
19
+ cellValuesByFieldId: AIRTABLE_FIELDS_BY_ID_SCHEMA,
20
+ }),
21
+ previous: z
22
+ .looseObject({ cellValuesByFieldId: AIRTABLE_FIELDS_BY_ID_SCHEMA })
23
+ .optional(),
24
+ unchanged: z
25
+ .looseObject({ cellValuesByFieldId: AIRTABLE_FIELDS_BY_ID_SCHEMA })
26
+ .optional(),
27
+ })
28
+ const AIRTABLE_VIEW_CHANGE_SCHEMA = z.looseObject({
29
+ changedRecordsById: z
30
+ .record(z.string(), AIRTABLE_CHANGED_RECORD_SCHEMA)
31
+ .optional(),
32
+ createdRecordsById: z
33
+ .record(z.string(), AIRTABLE_CREATED_RECORD_SCHEMA)
34
+ .optional(),
35
+ destroyedRecordIds: z.string().array().optional(),
36
+ })
37
+ const AIRTABLE_TABLE_CHANGE_SCHEMA = z.looseObject({
38
+ changedRecordsById: z
39
+ .record(z.string(), AIRTABLE_CHANGED_RECORD_SCHEMA)
40
+ .optional(),
41
+ changedViewsById: z
42
+ .record(z.string(), AIRTABLE_VIEW_CHANGE_SCHEMA)
43
+ .optional(),
44
+ createdRecordsById: z
45
+ .record(z.string(), AIRTABLE_CREATED_RECORD_SCHEMA)
46
+ .optional(),
47
+ destroyedRecordIds: z.string().array().optional(),
48
+ })
49
+
50
+ /** One provider-native Airtable webhook transaction payload. */
51
+ export const AIRTABLE_WEBHOOK_PAYLOAD_SCHEMA = z
52
+ .looseObject({
53
+ actionMetadata: AIRTABLE_ACTION_METADATA_SCHEMA,
54
+ baseTransactionNumber: z.number().int().nonnegative(),
55
+ changedTablesById: z
56
+ .record(z.string(), AIRTABLE_TABLE_CHANGE_SCHEMA)
57
+ .optional(),
58
+ code: z.string().optional(),
59
+ error: z.literal(true).optional(),
60
+ payloadFormat: z.string(),
61
+ timestamp: z.iso.datetime({ offset: true }),
62
+ })
63
+ .catchall(z.json())
64
+
65
+ const AIRTABLE_RECORD_EVENT_SCHEMA = z.object({
66
+ /** Airtable base containing the affected record. */
67
+ baseId: z.string(),
68
+
69
+ /** Complete provider webhook transaction. */
70
+ event: AIRTABLE_WEBHOOK_PAYLOAD_SCHEMA,
71
+
72
+ /** Time at which Airtable committed the transaction. */
73
+ occurredAt: z.iso.datetime({ offset: true }),
74
+
75
+ /** Stable Airtable record ID. */
76
+ recordId: z.string(),
77
+
78
+ /** Airtable system that caused the transaction. */
79
+ source: z.string(),
80
+
81
+ /** Provider-specific actor or source details. */
82
+ sourceMetadata: z.record(z.string(), z.json()).optional(),
83
+
84
+ /** Stable Airtable table ID. */
85
+ tableId: z.string(),
86
+
87
+ /** Base-scoped transaction number assigned by Airtable. */
88
+ transactionNumber: z.number().int().nonnegative(),
89
+ })
90
+
91
+ export const AIRTABLE_RECORD_CREATED_EVENT_SCHEMA =
92
+ AIRTABLE_RECORD_EVENT_SCHEMA.extend({
93
+ /** Time at which Airtable originally created the record. */
94
+ createdAt: z.iso.datetime({ offset: true }),
95
+
96
+ /** Current cell values keyed by stable field ID. */
97
+ fields: AIRTABLE_FIELDS_BY_ID_SCHEMA,
98
+ })
99
+
100
+ export const AIRTABLE_RECORD_UPDATED_EVENT_SCHEMA =
101
+ AIRTABLE_RECORD_EVENT_SCHEMA.extend({
102
+ /** Stable IDs of fields changed by this transaction. */
103
+ changedFieldIds: z.string().array(),
104
+
105
+ /** Current cell values keyed by stable field ID. */
106
+ fields: AIRTABLE_FIELDS_BY_ID_SCHEMA,
107
+
108
+ /** Cell values before this transaction, keyed by stable field ID. */
109
+ previousFields: AIRTABLE_FIELDS_BY_ID_SCHEMA,
110
+ })
111
+
112
+ export const AIRTABLE_RECORD_DELETED_EVENT_SCHEMA = AIRTABLE_RECORD_EVENT_SCHEMA
113
+
114
+ export const AIRTABLE_RECORD_MOVED_INTO_VIEW_EVENT_SCHEMA =
115
+ AIRTABLE_RECORD_CREATED_EVENT_SCHEMA.extend({
116
+ /** Stable ID of the view the record entered. */
117
+ viewId: z.string(),
118
+ })
119
+
120
+ export const AIRTABLE_RECORD_MOVED_OUT_OF_VIEW_EVENT_SCHEMA =
121
+ AIRTABLE_RECORD_EVENT_SCHEMA.extend({
122
+ /** Stable ID of the view the record exited. */
123
+ viewId: z.string(),
124
+ })
125
+
126
+ export const AIRTABLE_RECORD_EVENT_TYPES = [
127
+ "airtable.record.created",
128
+ "airtable.record.updated",
129
+ "airtable.record.deleted",
130
+ "airtable.record.movedIntoView",
131
+ "airtable.record.movedOutOfView",
132
+ ] as const
133
+
134
+ export type AirtableRecordEventType =
135
+ (typeof AIRTABLE_RECORD_EVENT_TYPES)[number]
136
+
137
+ /**
138
+ * Expands one Airtable webhook transaction into semantic record events.
139
+ *
140
+ * @param value - Untrusted provider payload returned by Airtable.
141
+ * @param baseId - Stable ID of the base that owns the webhook.
142
+ */
143
+ export function normalizeAirtableRecordEvents(value: unknown, baseId: string) {
144
+ const event = AIRTABLE_WEBHOOK_PAYLOAD_SCHEMA.parse(value)
145
+
146
+ return Object.entries(event.changedTablesById ?? {}).flatMap(
147
+ ([tableId, table]) => [
148
+ ...Object.entries(table.createdRecordsById ?? {}).map(
149
+ ([recordId, record]) => ({
150
+ eventType: "airtable.record.created" as const,
151
+ payload: AIRTABLE_RECORD_CREATED_EVENT_SCHEMA.parse({
152
+ ...recordEventBase(event, baseId, tableId, recordId),
153
+ createdAt: record.createdTime,
154
+ fields: record.cellValuesByFieldId,
155
+ }),
156
+ }),
157
+ ),
158
+ ...Object.entries(table.changedRecordsById ?? {}).map(
159
+ ([recordId, record]) => ({
160
+ eventType: "airtable.record.updated" as const,
161
+ payload: AIRTABLE_RECORD_UPDATED_EVENT_SCHEMA.parse({
162
+ ...recordEventBase(event, baseId, tableId, recordId),
163
+ changedFieldIds: Object.keys(record.current.cellValuesByFieldId),
164
+ fields: {
165
+ ...record.unchanged?.cellValuesByFieldId,
166
+ ...record.current.cellValuesByFieldId,
167
+ },
168
+ previousFields: {
169
+ ...record.unchanged?.cellValuesByFieldId,
170
+ ...record.previous?.cellValuesByFieldId,
171
+ },
172
+ }),
173
+ }),
174
+ ),
175
+ ...(table.destroyedRecordIds ?? []).map((recordId) => ({
176
+ eventType: "airtable.record.deleted" as const,
177
+ payload: AIRTABLE_RECORD_DELETED_EVENT_SCHEMA.parse(
178
+ recordEventBase(event, baseId, tableId, recordId),
179
+ ),
180
+ })),
181
+ ...Object.entries(table.changedViewsById ?? {}).flatMap(
182
+ ([viewId, view]) => [
183
+ ...Object.entries(view.createdRecordsById ?? {}).map(
184
+ ([recordId, record]) => ({
185
+ eventType: "airtable.record.movedIntoView" as const,
186
+ payload: AIRTABLE_RECORD_MOVED_INTO_VIEW_EVENT_SCHEMA.parse({
187
+ ...recordEventBase(event, baseId, tableId, recordId),
188
+ createdAt: record.createdTime,
189
+ fields: record.cellValuesByFieldId,
190
+ viewId,
191
+ }),
192
+ }),
193
+ ),
194
+ ...(view.destroyedRecordIds ?? []).map((recordId) => ({
195
+ eventType: "airtable.record.movedOutOfView" as const,
196
+ payload: AIRTABLE_RECORD_MOVED_OUT_OF_VIEW_EVENT_SCHEMA.parse({
197
+ ...recordEventBase(event, baseId, tableId, recordId),
198
+ viewId,
199
+ }),
200
+ })),
201
+ ],
202
+ ),
203
+ ],
204
+ )
205
+ }
206
+
207
+ /**
208
+ * Builds fields shared by every normalized Airtable record event.
209
+ *
210
+ * @param event - Parsed provider transaction.
211
+ * @param baseId - Base containing the changed record.
212
+ * @param tableId - Table containing the changed record.
213
+ * @param recordId - Stable ID of the changed record.
214
+ */
215
+ function recordEventBase(
216
+ event: z.output<typeof AIRTABLE_WEBHOOK_PAYLOAD_SCHEMA>,
217
+ baseId: string,
218
+ tableId: string,
219
+ recordId: string,
220
+ ) {
221
+ return {
222
+ baseId,
223
+ event,
224
+ occurredAt: event.timestamp,
225
+ recordId,
226
+ source: event.actionMetadata.source,
227
+ sourceMetadata: event.actionMetadata.sourceMetadata,
228
+ tableId,
229
+ transactionNumber: event.baseTransactionNumber,
230
+ }
231
+ }
@@ -0,0 +1,171 @@
1
+ import type { JsonObject } from "type-fest"
2
+ import { z } from "zod"
3
+
4
+ const ASANA_API_BASE_URL = "https://app.asana.com/api/1.0"
5
+ const ASANA_SECRET_SCHEMA = z.object({
6
+ accessToken: z.string().min(1),
7
+ })
8
+ const ASANA_ERROR_RESPONSE_SCHEMA = z.looseObject({
9
+ errors: z
10
+ .looseObject({
11
+ help: z.string().optional(),
12
+ message: z.string(),
13
+ phrase: z.string().optional(),
14
+ })
15
+ .array()
16
+ .optional(),
17
+ })
18
+
19
+ /** Scalar value serialized into one Asana query parameter. */
20
+ type AsanaQueryValue = boolean | number | string | undefined
21
+
22
+ /** Options for an authenticated Asana REST API request. */
23
+ export interface AsanaApiCallOptions<TSchema extends z.ZodType> {
24
+ /**
25
+ * Provider-native JSON body. Automatically wrapped in Asana's `data`
26
+ * envelope.
27
+ */
28
+ body?: JsonObject
29
+
30
+ /** HTTP method. Defaults to `POST` with a body and `GET` otherwise. */
31
+ httpMethod?: "DELETE" | "GET" | "POST" | "PUT"
32
+
33
+ /** Provider-native URL query parameters. */
34
+ query?: Record<string, AsanaQueryValue>
35
+
36
+ /** Schema for the complete successful Asana response envelope. */
37
+ responseSchema: TSchema
38
+ }
39
+
40
+ /** Authenticated Asana REST API helper for custom actions. */
41
+ export interface AsanaApi {
42
+ /**
43
+ * Calls an Asana REST endpoint and validates its successful response.
44
+ *
45
+ * @param path - API path such as `/tasks/123`.
46
+ * @param options - Request data and response schema.
47
+ */
48
+ call<TSchema extends z.ZodType>(
49
+ path: string,
50
+ options: AsanaApiCallOptions<TSchema>,
51
+ ): Promise<z.output<TSchema>>
52
+ }
53
+
54
+ /** Structured error returned by an authenticated Asana API request. */
55
+ export class AsanaApiError extends Error {
56
+ /** Asana troubleshooting link, when supplied. */
57
+ readonly help?: string
58
+
59
+ /** API path that failed. */
60
+ readonly path: string
61
+
62
+ /** Asana support phrase for provider-side errors. */
63
+ readonly phrase?: string
64
+
65
+ /** Retry delay from Asana's `Retry-After` header, in seconds. */
66
+ readonly retryAfter?: number
67
+
68
+ /** HTTP status returned by Asana. */
69
+ readonly status: number
70
+
71
+ /**
72
+ * Creates a structured Asana API error.
73
+ *
74
+ * @param options - Provider and transport error details.
75
+ * @param options.help - Provider troubleshooting link.
76
+ * @param options.message - Human-readable error message.
77
+ * @param options.path - API path that failed.
78
+ * @param options.phrase - Asana support phrase.
79
+ * @param options.retryAfter - Retry delay in seconds.
80
+ * @param options.status - HTTP response status.
81
+ */
82
+ constructor(options: {
83
+ help?: string
84
+ message: string
85
+ path: string
86
+ phrase?: string
87
+ retryAfter?: number
88
+ status: number
89
+ }) {
90
+ super(`Asana ${options.path} failed: ${options.message}`)
91
+ this.name = "AsanaApiError"
92
+ this.help = options.help
93
+ this.path = options.path
94
+ this.phrase = options.phrase
95
+ this.retryAfter = options.retryAfter
96
+ this.status = options.status
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Creates a raw authenticated Asana REST API helper.
102
+ *
103
+ * Use this escape hatch for endpoints without packaged actions. Callers provide
104
+ * a Zod schema so custom responses remain validated at the provider boundary.
105
+ *
106
+ * @param secret - Resolved Asana integration secret.
107
+ */
108
+ export function getAsanaApi(secret: Record<string, unknown>): AsanaApi {
109
+ const { accessToken } = ASANA_SECRET_SCHEMA.parse(secret)
110
+
111
+ return {
112
+ call: async (path, options) => {
113
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`
114
+ const url = new URL(`${ASANA_API_BASE_URL}${normalizedPath}`)
115
+ for (const [name, value] of Object.entries(options.query ?? {})) {
116
+ if (value !== undefined) url.searchParams.set(name, String(value))
117
+ }
118
+
119
+ const response = await fetch(url, {
120
+ body: options.body ? JSON.stringify({ data: options.body }) : undefined,
121
+ headers: {
122
+ Accept: "application/json",
123
+ Authorization: `Bearer ${accessToken}`,
124
+ ...(options.body && { "Content-Type": "application/json" }),
125
+ },
126
+ method:
127
+ options.httpMethod ?? (options.body === undefined ? "GET" : "POST"),
128
+ })
129
+ const responseBody = await response.text()
130
+ let payload: unknown
131
+ try {
132
+ payload = JSON.parse(responseBody)
133
+ } catch (cause) {
134
+ if (response.ok) throw cause
135
+ throw new AsanaApiError({
136
+ message: responseBody.trim() || `HTTP ${response.status}`,
137
+ path: normalizedPath,
138
+ retryAfter: parseRetryAfter(response.headers.get("Retry-After")),
139
+ status: response.status,
140
+ })
141
+ }
142
+ if (!response.ok) {
143
+ const errorResult = ASANA_ERROR_RESPONSE_SCHEMA.safeParse(payload)
144
+ const error = errorResult.success
145
+ ? errorResult.data.errors?.[0]
146
+ : undefined
147
+ throw new AsanaApiError({
148
+ help: error?.help,
149
+ message: error?.message ?? `HTTP ${response.status}`,
150
+ path: normalizedPath,
151
+ phrase: error?.phrase,
152
+ retryAfter: parseRetryAfter(response.headers.get("Retry-After")),
153
+ status: response.status,
154
+ })
155
+ }
156
+
157
+ return options.responseSchema.parse(payload)
158
+ },
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Parses Asana's integer retry delay header.
164
+ *
165
+ * @param value - Raw `Retry-After` header.
166
+ */
167
+ function parseRetryAfter(value: string | null) {
168
+ if (value === null) return undefined
169
+ const seconds = Number(value)
170
+ return Number.isFinite(seconds) ? seconds : undefined
171
+ }
@@ -0,0 +1,49 @@
1
+ import { z } from "zod"
2
+ import {
3
+ ASANA_COMMENT_ADDED_EVENT_SCHEMA,
4
+ ASANA_EVENT_SCHEMA,
5
+ ASANA_TASK_ADDED_EVENT_SCHEMA,
6
+ ASANA_TASK_CHANGED_EVENT_SCHEMA,
7
+ ASANA_TASK_COMPLETED_EVENT_SCHEMA,
8
+ ASANA_TASK_DELETED_EVENT_SCHEMA,
9
+ ASANA_TASK_REMOVED_EVENT_SCHEMA,
10
+ } from "./schemas"
11
+
12
+ export * from "./api"
13
+ export * from "./schemas"
14
+
15
+ /** Asana resource selected for one webhook subscription. */
16
+ export const ASANA_TRIGGER_CONFIG_SCHEMA = z.object({
17
+ resourceId: z.string(),
18
+ })
19
+
20
+ export const asanaTriggerContracts = {
21
+ "asana.comment.added": {
22
+ configSchema: ASANA_TRIGGER_CONFIG_SCHEMA,
23
+ eventSchema: ASANA_COMMENT_ADDED_EVENT_SCHEMA,
24
+ },
25
+ "asana.event": {
26
+ configSchema: ASANA_TRIGGER_CONFIG_SCHEMA,
27
+ eventSchema: ASANA_EVENT_SCHEMA,
28
+ },
29
+ "asana.task.added": {
30
+ configSchema: ASANA_TRIGGER_CONFIG_SCHEMA,
31
+ eventSchema: ASANA_TASK_ADDED_EVENT_SCHEMA,
32
+ },
33
+ "asana.task.changed": {
34
+ configSchema: ASANA_TRIGGER_CONFIG_SCHEMA,
35
+ eventSchema: ASANA_TASK_CHANGED_EVENT_SCHEMA,
36
+ },
37
+ "asana.task.completed": {
38
+ configSchema: ASANA_TRIGGER_CONFIG_SCHEMA,
39
+ eventSchema: ASANA_TASK_COMPLETED_EVENT_SCHEMA,
40
+ },
41
+ "asana.task.deleted": {
42
+ configSchema: ASANA_TRIGGER_CONFIG_SCHEMA,
43
+ eventSchema: ASANA_TASK_DELETED_EVENT_SCHEMA,
44
+ },
45
+ "asana.task.removed": {
46
+ configSchema: ASANA_TRIGGER_CONFIG_SCHEMA,
47
+ eventSchema: ASANA_TASK_REMOVED_EVENT_SCHEMA,
48
+ },
49
+ } as const