@automate.ax/integration-contracts 0.141.0 → 0.142.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.
@@ -0,0 +1,324 @@
1
+ import * as z from "zod"
2
+
3
+ export const CLICKUP_USER_SCHEMA = z.object({
4
+ color: z.string().nullable().optional(),
5
+ email: z.email().optional(),
6
+ id: z.number().int(),
7
+ initials: z.string().optional(),
8
+ profilePicture: z.url().nullable().optional(),
9
+ role: z.number().int().optional(),
10
+ username: z.string(),
11
+ })
12
+
13
+ export const CLICKUP_WORKSPACE_SCHEMA = z.object({
14
+ avatar: z.url().nullable().optional(),
15
+ color: z.string().nullable().optional(),
16
+ id: z.string(),
17
+ members: z.object({ user: CLICKUP_USER_SCHEMA }).array().prefault([]),
18
+ name: z.string(),
19
+ })
20
+
21
+ export const CLICKUP_STATUS_SCHEMA = z.object({
22
+ color: z.string().optional(),
23
+ orderindex: z.number().optional(),
24
+ status: z.string(),
25
+ type: z.string().optional(),
26
+ })
27
+
28
+ export const CLICKUP_SPACE_SCHEMA = z.object({
29
+ archived: z.boolean().prefault(false),
30
+ color: z.string().nullable().optional(),
31
+ id: z.string(),
32
+ multipleAssignees: z.boolean().optional(),
33
+ name: z.string(),
34
+ private: z.boolean().optional(),
35
+ statuses: CLICKUP_STATUS_SCHEMA.array().prefault([]),
36
+ })
37
+
38
+ export const CLICKUP_FOLDER_SCHEMA: z.ZodType<{
39
+ folders: z.output<typeof CLICKUP_FOLDER_SCHEMA>[]
40
+ hidden?: boolean
41
+ id: string
42
+ lists: z.output<typeof CLICKUP_LIST_SCHEMA>[]
43
+ name: string
44
+ orderindex?: number
45
+ overrideStatuses?: boolean
46
+ parentFolder?: string
47
+ space?: { id: string; name?: string }
48
+ taskCount?: string
49
+ }> = z.object({
50
+ folders: z.lazy(() => CLICKUP_FOLDER_SCHEMA.array()).prefault([]),
51
+ hidden: z.boolean().optional(),
52
+ id: z.string(),
53
+ lists: z.lazy(() => CLICKUP_LIST_SCHEMA.array()).prefault([]),
54
+ name: z.string(),
55
+ orderindex: z.number().optional(),
56
+ overrideStatuses: z.boolean().optional(),
57
+ parentFolder: z.string().optional(),
58
+ space: z.object({ id: z.string(), name: z.string().optional() }).optional(),
59
+ taskCount: z
60
+ .string()
61
+ .nullable()
62
+ .optional()
63
+ .transform((value) => value ?? undefined),
64
+ })
65
+
66
+ export const CLICKUP_LIST_SCHEMA = z.object({
67
+ archived: z.boolean().optional(),
68
+ content: z.string().optional(),
69
+ dueDate: z.string().nullable().optional(),
70
+ dueDateTime: z.boolean().optional(),
71
+ folder: z
72
+ .object({
73
+ hidden: z.boolean().optional(),
74
+ id: z.string(),
75
+ name: z.string().optional(),
76
+ })
77
+ .optional(),
78
+ id: z.string(),
79
+ name: z.string(),
80
+ orderindex: z.number().optional(),
81
+ space: z.object({ id: z.string(), name: z.string().optional() }).optional(),
82
+ statuses: CLICKUP_STATUS_SCHEMA.array().prefault([]),
83
+ taskCount: z.string().nullable().optional(),
84
+ })
85
+
86
+ export const CLICKUP_CUSTOM_FIELD_SCHEMA = z.object({
87
+ id: z.string(),
88
+ name: z.string(),
89
+ required: z.boolean().optional(),
90
+ type: z.string(),
91
+ typeConfig: z.json().optional(),
92
+ value: z.json().optional(),
93
+ })
94
+
95
+ const CLICKUP_TASK_BASE_SCHEMA = z.object({
96
+ archived: z.boolean().prefault(false),
97
+ assignees: CLICKUP_USER_SCHEMA.array().prefault([]),
98
+ creator: CLICKUP_USER_SCHEMA.optional(),
99
+ customFields: CLICKUP_CUSTOM_FIELD_SCHEMA.array().prefault([]),
100
+ dateClosed: z.string().nullable().optional(),
101
+ dateCreated: z.string().optional(),
102
+ dateDone: z.string().nullable().optional(),
103
+ dateUpdated: z.string().optional(),
104
+ description: z.string().optional(),
105
+ dueDate: z.string().nullable().optional(),
106
+ id: z.string(),
107
+ list: z.object({ id: z.string(), name: z.string().optional() }).optional(),
108
+ name: z.string(),
109
+ parent: z.string().nullable().optional(),
110
+ priority: z
111
+ .object({
112
+ color: z.string().optional(),
113
+ id: z.string().optional(),
114
+ orderindex: z.string().optional(),
115
+ priority: z.string(),
116
+ })
117
+ .nullable()
118
+ .optional(),
119
+ space: z.object({ id: z.string() }).optional(),
120
+ startDate: z.string().nullable().optional(),
121
+ status: CLICKUP_STATUS_SCHEMA.optional(),
122
+ tags: z
123
+ .object({
124
+ name: z.string(),
125
+ tagBg: z.string().optional(),
126
+ tagFg: z.string().optional(),
127
+ })
128
+ .array()
129
+ .prefault([]),
130
+ textContent: z.string().optional(),
131
+ timeEstimate: z.coerce.number().nullable().optional(),
132
+ timeSpent: z.number().optional(),
133
+ url: z.url().optional(),
134
+ watchers: CLICKUP_USER_SCHEMA.array().prefault([]),
135
+ })
136
+
137
+ export type ClickUpTask = z.output<typeof CLICKUP_TASK_BASE_SCHEMA> & {
138
+ subtasks: ClickUpTask[]
139
+ }
140
+
141
+ export const CLICKUP_TASK_SCHEMA: z.ZodType<ClickUpTask> =
142
+ CLICKUP_TASK_BASE_SCHEMA.extend({
143
+ subtasks: z.lazy(() => CLICKUP_TASK_SCHEMA.array()).prefault([]),
144
+ })
145
+
146
+ export const CLICKUP_COMMENT_SCHEMA = z.object({
147
+ assignee: CLICKUP_USER_SCHEMA.optional(),
148
+ comment: z.json().array().prefault([]),
149
+ commentText: z.string().optional(),
150
+ date: z.string(),
151
+ id: z.string(),
152
+ resolved: z.boolean().optional(),
153
+ user: CLICKUP_USER_SCHEMA,
154
+ })
155
+
156
+ export const CLICKUP_TIME_ENTRY_SCHEMA = z.object({
157
+ at: z.coerce.string().optional(),
158
+ billable: z.boolean().optional(),
159
+ description: z.string().optional(),
160
+ duration: z.coerce.string(),
161
+ end: z.coerce.string().optional(),
162
+ id: z.string(),
163
+ start: z.coerce.string(),
164
+ task: z
165
+ .object({ id: z.string(), name: z.string().optional() })
166
+ .nullable()
167
+ .optional(),
168
+ source: z.string().optional(),
169
+ tags: z.json().array().prefault([]),
170
+ taskLocation: z
171
+ .object({
172
+ folderId: z.union([z.number(), z.string()]).transform(String),
173
+ folderName: z.string(),
174
+ listId: z.union([z.number(), z.string()]).transform(String),
175
+ listName: z.string(),
176
+ spaceId: z.union([z.number(), z.string()]).transform(String),
177
+ spaceName: z.string(),
178
+ })
179
+ .optional(),
180
+ taskTags: z
181
+ .object({
182
+ creator: z.number().int().optional(),
183
+ name: z.string(),
184
+ tagBg: z.string().optional(),
185
+ tagFg: z.string().optional(),
186
+ })
187
+ .array()
188
+ .prefault([]),
189
+ taskUrl: z.url().optional(),
190
+ user: CLICKUP_USER_SCHEMA.optional(),
191
+ wid: z.string().optional(),
192
+ })
193
+
194
+ export const CLICKUP_KEY_RESULT_SCHEMA = z.object({
195
+ completed: z.boolean().optional(),
196
+ creator: z.number().int().optional(),
197
+ current: z.number().optional(),
198
+ dateCreated: z.string().optional(),
199
+ goalId: z.string().optional(),
200
+ goalPrettyId: z.string().optional(),
201
+ id: z.string(),
202
+ lastAction: z.json().optional(),
203
+ name: z.string(),
204
+ owners: CLICKUP_USER_SCHEMA.array().prefault([]),
205
+ percentCompleted: z.coerce.number().nullable().optional(),
206
+ subcategoryIds: z.string().array().prefault([]),
207
+ stepsCurrent: z.number().nullable().optional(),
208
+ stepsEnd: z.number().optional(),
209
+ stepsStart: z.number().optional(),
210
+ taskIds: z.string().array().prefault([]),
211
+ target: z.number().optional(),
212
+ type: z.string().optional(),
213
+ unit: z.string().optional(),
214
+ })
215
+
216
+ const CLICKUP_GOAL_BASE_SCHEMA = z.object({
217
+ archived: z.boolean().optional(),
218
+ color: z.string().optional(),
219
+ dateCreated: z.string().optional(),
220
+ description: z.string().optional(),
221
+ dueDate: z.string().nullable().optional(),
222
+ id: z.string(),
223
+ multipleOwners: z.boolean().optional(),
224
+ name: z.string(),
225
+ percentCompleted: z.number().optional(),
226
+ private: z.boolean().optional(),
227
+ teamId: z.string().optional(),
228
+ })
229
+
230
+ /** Goal shape returned by the Workspace Goal listing endpoint. */
231
+ export const CLICKUP_GOAL_LIST_ITEM_SCHEMA = CLICKUP_GOAL_BASE_SCHEMA.extend({
232
+ keyResults: z.string().array().prefault([]),
233
+ owners: z.string().array().prefault([]),
234
+ })
235
+
236
+ /** Goal shape returned by get, create, and update endpoints. */
237
+ export const CLICKUP_GOAL_SCHEMA = CLICKUP_GOAL_BASE_SCHEMA.extend({
238
+ keyResults: z.string().array().prefault([]),
239
+ owners: CLICKUP_USER_SCHEMA.array().prefault([]),
240
+ })
241
+
242
+ export const CLICKUP_HISTORY_ITEM_SCHEMA = z.object({
243
+ after: z.json().optional(),
244
+ before: z.json().optional(),
245
+ comment: z
246
+ .object({
247
+ comment: z.json().array().prefault([]),
248
+ date: z.string(),
249
+ id: z.string(),
250
+ parent: z.string().optional(),
251
+ textContent: z.string().optional(),
252
+ type: z.number().int().optional(),
253
+ user: CLICKUP_USER_SCHEMA,
254
+ })
255
+ .catchall(z.json())
256
+ .optional(),
257
+ customField: CLICKUP_CUSTOM_FIELD_SCHEMA.optional(),
258
+ data: z.json().optional(),
259
+ date: z.string(),
260
+ field: z.string().optional(),
261
+ id: z.string(),
262
+ parentId: z.string().optional(),
263
+ source: z.json().optional(),
264
+ type: z.number().int(),
265
+ user: CLICKUP_USER_SCHEMA.optional(),
266
+ })
267
+
268
+ export const CLICKUP_WEBHOOK_EVENT_NAMES = [
269
+ "taskCreated",
270
+ "taskUpdated",
271
+ "taskDeleted",
272
+ "taskPriorityUpdated",
273
+ "taskStatusUpdated",
274
+ "taskAssigneeUpdated",
275
+ "taskDueDateUpdated",
276
+ "taskTagUpdated",
277
+ "taskMoved",
278
+ "taskCommentPosted",
279
+ "taskCommentUpdated",
280
+ "taskTimeEstimateUpdated",
281
+ "taskTimeTrackedUpdated",
282
+ "listCreated",
283
+ "listUpdated",
284
+ "listDeleted",
285
+ "folderCreated",
286
+ "folderUpdated",
287
+ "folderDeleted",
288
+ "spaceCreated",
289
+ "spaceUpdated",
290
+ "spaceDeleted",
291
+ "goalCreated",
292
+ "goalUpdated",
293
+ "goalDeleted",
294
+ "keyResultCreated",
295
+ "keyResultUpdated",
296
+ "keyResultDeleted",
297
+ ] as const
298
+
299
+ export const CLICKUP_WEBHOOK_EVENT_NAME_SCHEMA = z.enum(
300
+ CLICKUP_WEBHOOK_EVENT_NAMES,
301
+ )
302
+
303
+ export const CLICKUP_WEBHOOK_EVENT_SCHEMA = z.object({
304
+ data: z
305
+ .object({
306
+ description: z.string().optional(),
307
+ intervalId: z.string().optional(),
308
+ })
309
+ .catchall(z.json())
310
+ .optional(),
311
+ event: CLICKUP_WEBHOOK_EVENT_NAME_SCHEMA,
312
+ folderId: z.string().optional(),
313
+ goalId: z.string().optional(),
314
+ historyItems: CLICKUP_HISTORY_ITEM_SCHEMA.array().prefault([]),
315
+ keyResultId: z.string().optional(),
316
+ listId: z.string().optional(),
317
+ spaceId: z.string().optional(),
318
+ taskId: z.string().optional(),
319
+ webhookId: z.string(),
320
+ })
321
+
322
+ export const CLICKUP_TRIGGER_CONFIG_SCHEMA = z.object({
323
+ workspaceId: z.string().min(1),
324
+ })
@@ -3,8 +3,12 @@ import * as z from "zod"
3
3
  export const CLOSEBOT_ID_SCHEMA = z.string().trim().min(1)
4
4
 
5
5
  export const CLOSEBOT_DATE_SCHEMA = z
6
- .union([z.date(), z.iso.datetime({ offset: true })])
7
- .transform((value) => (value instanceof Date ? value : new Date(value)))
6
+ .union([z.date(), z.iso.datetime({ local: true, offset: true })])
7
+ .transform((value) =>
8
+ value instanceof Date
9
+ ? value
10
+ : new Date(/(?:Z|[+-]\d{2}:\d{2})$/.test(value) ? value : `${value}Z`),
11
+ )
8
12
 
9
13
  const OPTIONAL_STRING = z.string().nullable().optional()
10
14
  const OPTIONAL_BOOLEAN = z.boolean().optional()
@@ -187,7 +191,7 @@ export const CLOSEBOT_BOT_SCHEMA = z.object({
187
191
  modifiedBy: OPTIONAL_STRING,
188
192
  name: OPTIONAL_STRING,
189
193
  personaIds: z.string().array().nullable().optional(),
190
- personaSplitTest: CLOSEBOT_PERSONA_SPLIT_TEST_SCHEMA.optional(),
194
+ personaSplitTest: CLOSEBOT_PERSONA_SPLIT_TEST_SCHEMA.nullable().optional(),
191
195
  personaWeights: z.record(z.string(), z.number().int()).nullable().optional(),
192
196
  reschedulingEnabled: OPTIONAL_BOOLEAN,
193
197
  smartFollowUp: OPTIONAL_BOOLEAN,
@@ -0,0 +1,151 @@
1
+ import * as z from "zod"
2
+
3
+ const GOOGLE_ADS_API_ORIGIN = "https://googleads.googleapis.com"
4
+ const GOOGLE_ADS_API_VERSION = "v25"
5
+
6
+ export const GOOGLE_ADS_CUSTOMER_ID_SCHEMA = z
7
+ .string()
8
+ .trim()
9
+ .regex(/^(?:\d{3}-?\d{3}-?\d{4})$/, "Enter a 10-digit customer ID.")
10
+ .transform((value) => value.replaceAll("-", ""))
11
+
12
+ export const GOOGLE_ADS_RESOURCE_NAME_SCHEMA = z
13
+ .string()
14
+ .regex(/^customers\/\d{10}\/[A-Za-z][A-Za-z0-9]*(?:\/[^/]+)+$/)
15
+
16
+ export const GOOGLE_ADS_SECRET_SCHEMA = z.object({
17
+ accessToken: z.string().min(1),
18
+ developerToken: z.string().min(1),
19
+ tokenType: z.string().min(1),
20
+ })
21
+
22
+ const GOOGLE_ADS_FAILURE_SCHEMA = z.looseObject({
23
+ error: z
24
+ .looseObject({
25
+ code: z.number().int().optional(),
26
+ message: z.string().optional(),
27
+ status: z.string().optional(),
28
+ })
29
+ .optional(),
30
+ })
31
+
32
+ export interface GoogleAdsRequestOptions<TSchema extends z.ZodType> {
33
+ body?: z.input<ReturnType<typeof z.json>>
34
+ loginCustomerId?: string
35
+ method?: "GET" | "POST"
36
+ responseSchema: TSchema
37
+ }
38
+
39
+ interface GoogleAdsApiErrorOptions {
40
+ message?: string
41
+ providerStatus?: string
42
+ requestId?: string
43
+ retryAfter?: string
44
+ status: number
45
+ }
46
+
47
+ /** Structured Google Ads REST failure with correlation metadata. */
48
+ export class GoogleAdsApiError extends Error {
49
+ readonly providerStatus?: string
50
+ readonly requestId?: string
51
+ readonly retryAfter?: string
52
+ readonly status: number
53
+
54
+ /** Creates a structured failure from one provider response. */
55
+ /** @param options - HTTP and Google Ads error metadata. */
56
+ constructor(options: GoogleAdsApiErrorOptions) {
57
+ super(
58
+ options.message ??
59
+ `Google Ads API request failed with status ${options.status}.`,
60
+ )
61
+ this.name = "GoogleAdsApiError"
62
+ this.providerStatus = options.providerStatus
63
+ this.requestId = options.requestId
64
+ this.retryAfter = options.retryAfter
65
+ this.status = options.status
66
+ }
67
+ }
68
+
69
+ /** Creates an authenticated Google Ads v25 REST client. */
70
+ /** @param secret - Resolved Google OAuth and platform developer credentials. */
71
+ export function getGoogleAdsApi(secret: unknown) {
72
+ const credentials = GOOGLE_ADS_SECRET_SCHEMA.parse(secret)
73
+
74
+ return {
75
+ async request<TSchema extends z.ZodType>(
76
+ path: string,
77
+ options: GoogleAdsRequestOptions<TSchema>,
78
+ ): Promise<z.output<TSchema>> {
79
+ const normalizedPath = path.replace(/^\/+/, "")
80
+ if (
81
+ !normalizedPath ||
82
+ normalizedPath.includes("://") ||
83
+ normalizedPath.includes("\\")
84
+ ) {
85
+ throw new TypeError("Google Ads API paths must be relative.")
86
+ }
87
+ const url = new URL(
88
+ `${GOOGLE_ADS_API_VERSION}/${normalizedPath}`,
89
+ `${GOOGLE_ADS_API_ORIGIN}/`,
90
+ )
91
+ if (url.origin !== GOOGLE_ADS_API_ORIGIN) {
92
+ throw new TypeError(
93
+ "Google Ads API paths must remain on googleads.googleapis.com.",
94
+ )
95
+ }
96
+
97
+ const headers = new Headers({
98
+ Accept: "application/json",
99
+ Authorization: `${credentials.tokenType} ${credentials.accessToken}`,
100
+ "developer-token": credentials.developerToken,
101
+ })
102
+ if (options.loginCustomerId) {
103
+ headers.set(
104
+ "login-customer-id",
105
+ GOOGLE_ADS_CUSTOMER_ID_SCHEMA.parse(options.loginCustomerId),
106
+ )
107
+ }
108
+ if (options.body !== undefined) {
109
+ headers.set("Content-Type", "application/json")
110
+ }
111
+
112
+ const response = await fetch(url, {
113
+ body:
114
+ options.body === undefined ? undefined : JSON.stringify(options.body),
115
+ headers,
116
+ method: options.method ?? (options.body === undefined ? "GET" : "POST"),
117
+ })
118
+ const payload = parseGoogleAdsJson(await response.text())
119
+ if (!response.ok) {
120
+ const failure = GOOGLE_ADS_FAILURE_SCHEMA.safeParse(payload)
121
+ throw new GoogleAdsApiError({
122
+ message: failure.success ? failure.data.error?.message : undefined,
123
+ providerStatus: failure.success
124
+ ? failure.data.error?.status
125
+ : undefined,
126
+ requestId: response.headers.get("request-id") ?? undefined,
127
+ retryAfter: response.headers.get("retry-after") ?? undefined,
128
+ status: response.status,
129
+ })
130
+ }
131
+ return options.responseSchema.parse(payload)
132
+ },
133
+ }
134
+ }
135
+
136
+ /** Normalizes a Google Ads customer ID for paths and headers. */
137
+ /** @param value - Dashed or compact 10-digit customer ID. */
138
+ export function normalizeGoogleAdsCustomerId(value: string) {
139
+ return GOOGLE_ADS_CUSTOMER_ID_SCHEMA.parse(value)
140
+ }
141
+
142
+ /** Parses an optional Google Ads JSON response body. */
143
+ /** @param value - Raw response body. */
144
+ function parseGoogleAdsJson(value: string): unknown {
145
+ if (!value) return undefined
146
+ try {
147
+ return JSON.parse(value)
148
+ } catch {
149
+ return value
150
+ }
151
+ }
@@ -0,0 +1,131 @@
1
+ import type * as z from "zod"
2
+ import {
3
+ GOOGLE_ADS_CHANGE_EVENT_PAYLOAD_SCHEMA,
4
+ GOOGLE_ADS_CHANGE_TRIGGER_CONFIG_SCHEMA,
5
+ } from "./schemas"
6
+
7
+ const changeContract = {
8
+ configSchema: GOOGLE_ADS_CHANGE_TRIGGER_CONFIG_SCHEMA,
9
+ eventSchema: GOOGLE_ADS_CHANGE_EVENT_PAYLOAD_SCHEMA,
10
+ }
11
+
12
+ export const googleAdsTriggerContracts = {
13
+ "googleAds.adGroup.created": changeContract,
14
+ "googleAds.adGroup.removed": changeContract,
15
+ "googleAds.adGroup.updated": changeContract,
16
+ "googleAds.adGroupAd.created": changeContract,
17
+ "googleAds.adGroupAd.removed": changeContract,
18
+ "googleAds.adGroupAd.updated": changeContract,
19
+ "googleAds.adGroupAsset.created": changeContract,
20
+ "googleAds.adGroupAsset.removed": changeContract,
21
+ "googleAds.adGroupAsset.updated": changeContract,
22
+ "googleAds.asset.created": changeContract,
23
+ "googleAds.asset.removed": changeContract,
24
+ "googleAds.asset.updated": changeContract,
25
+ "googleAds.campaign.created": changeContract,
26
+ "googleAds.campaign.removed": changeContract,
27
+ "googleAds.campaign.updated": changeContract,
28
+ "googleAds.campaignAsset.created": changeContract,
29
+ "googleAds.campaignAsset.removed": changeContract,
30
+ "googleAds.campaignAsset.updated": changeContract,
31
+ "googleAds.campaignBudget.created": changeContract,
32
+ "googleAds.campaignBudget.removed": changeContract,
33
+ "googleAds.campaignBudget.updated": changeContract,
34
+ "googleAds.change": changeContract,
35
+ } as const
36
+
37
+ export type GoogleAdsEventType = keyof typeof googleAdsTriggerContracts
38
+
39
+ /**
40
+ * Returns the broad and optional semantic event types for one change.
41
+ *
42
+ * @param event - Normalized Google Ads change event.
43
+ */
44
+ export function getGoogleAdsChangeEventTypes(
45
+ event: z.output<typeof GOOGLE_ADS_CHANGE_EVENT_PAYLOAD_SCHEMA>,
46
+ ): GoogleAdsEventType[] {
47
+ const semanticType = getSemanticEventType(
48
+ event.event.changeResourceType,
49
+ event.event.resourceChangeOperation,
50
+ )
51
+ return semanticType
52
+ ? ["googleAds.change", semanticType]
53
+ : ["googleAds.change"]
54
+ }
55
+
56
+ /**
57
+ * Maps provider resource and operation enums to public event types.
58
+ *
59
+ * @param resource - Provider change resource enum.
60
+ * @param operation - Provider mutation operation.
61
+ */
62
+ function getSemanticEventType(
63
+ resource: z.output<
64
+ typeof GOOGLE_ADS_CHANGE_EVENT_PAYLOAD_SCHEMA
65
+ >["event"]["changeResourceType"],
66
+ operation: z.output<
67
+ typeof GOOGLE_ADS_CHANGE_EVENT_PAYLOAD_SCHEMA
68
+ >["event"]["resourceChangeOperation"],
69
+ ): GoogleAdsEventType | undefined {
70
+ if (operation === "UNSPECIFIED" || operation === "UNKNOWN") return undefined
71
+ switch (resource) {
72
+ case "AD_GROUP":
73
+ return (
74
+ {
75
+ CREATE: "googleAds.adGroup.created",
76
+ REMOVE: "googleAds.adGroup.removed",
77
+ UPDATE: "googleAds.adGroup.updated",
78
+ } as const
79
+ )[operation]
80
+ case "AD_GROUP_AD":
81
+ return (
82
+ {
83
+ CREATE: "googleAds.adGroupAd.created",
84
+ REMOVE: "googleAds.adGroupAd.removed",
85
+ UPDATE: "googleAds.adGroupAd.updated",
86
+ } as const
87
+ )[operation]
88
+ case "AD_GROUP_ASSET":
89
+ return (
90
+ {
91
+ CREATE: "googleAds.adGroupAsset.created",
92
+ REMOVE: "googleAds.adGroupAsset.removed",
93
+ UPDATE: "googleAds.adGroupAsset.updated",
94
+ } as const
95
+ )[operation]
96
+ case "ASSET":
97
+ return (
98
+ {
99
+ CREATE: "googleAds.asset.created",
100
+ REMOVE: "googleAds.asset.removed",
101
+ UPDATE: "googleAds.asset.updated",
102
+ } as const
103
+ )[operation]
104
+ case "CAMPAIGN":
105
+ return (
106
+ {
107
+ CREATE: "googleAds.campaign.created",
108
+ REMOVE: "googleAds.campaign.removed",
109
+ UPDATE: "googleAds.campaign.updated",
110
+ } as const
111
+ )[operation]
112
+ case "CAMPAIGN_ASSET":
113
+ return (
114
+ {
115
+ CREATE: "googleAds.campaignAsset.created",
116
+ REMOVE: "googleAds.campaignAsset.removed",
117
+ UPDATE: "googleAds.campaignAsset.updated",
118
+ } as const
119
+ )[operation]
120
+ case "CAMPAIGN_BUDGET":
121
+ return (
122
+ {
123
+ CREATE: "googleAds.campaignBudget.created",
124
+ REMOVE: "googleAds.campaignBudget.removed",
125
+ UPDATE: "googleAds.campaignBudget.updated",
126
+ } as const
127
+ )[operation]
128
+ default:
129
+ return undefined
130
+ }
131
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./api"
2
+ export * from "./events"
3
+ export * from "./schemas"