-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathusers.ts
More file actions
330 lines (300 loc) · 10.8 KB
/
users.ts
File metadata and controls
330 lines (300 loc) · 10.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
import { z } from "zod";
import { FlexibleTimestampSchema, IterableDateTimeSchema } from "./common.js";
import { EventRecordSchema } from "./events.js";
/**
* User management schemas and types
*/
export const UserProfileSchema = z.object({
email: z.email(),
userId: z.string().optional(),
dataFields: z.record(z.string(), z.any()).optional(),
preferUserId: z.boolean().optional(),
mergeNestedObjects: z.boolean().optional(),
});
export type UserProfile = z.infer<typeof UserProfileSchema>;
export type UpdateUserParams = z.infer<typeof UpdateUserParamsSchema>;
export const UserResponseSchema = z.object({
user: z
.object({
email: z.string(),
userId: z.string().optional(),
dataFields: z.record(z.string(), z.any()).optional(),
profileUpdatedAt: z.string().optional(),
})
.optional(), // user field is undefined when user not found
});
export type UserResponse = z.infer<typeof UserResponseSchema>;
export const GetUserByEmailParamsSchema = z.object({
email: z.email().describe("Email address of the user to retrieve"),
});
export type GetUserByEmailParams = z.infer<typeof GetUserByEmailParamsSchema>;
export const UpdateUserParamsSchema = z
.object({
email: z.email().optional().describe("User email address"),
userId: z.string().optional().describe("User ID (alternative to email)"),
dataFields: z
.record(z.string(), z.any())
.optional()
.describe("User data fields to update"),
mergeNestedObjects: z
.boolean()
.optional()
.describe("Merge top-level objects instead of overwriting them"),
createNewFields: z
.boolean()
.optional()
.describe(
"Whether new fields should be ingested and added to the schema"
),
preferUserId: z
.boolean()
.optional()
.describe(
"Whether to create new user if userId doesn't exist (email-based projects only)"
),
})
.refine(
(data) => data.email || data.userId,
"Either email or userId must be provided"
);
export const GetUserByIdParamsSchema = z.object({
userId: z.string().describe("User ID to retrieve"),
});
export type GetUserByIdParams = z.infer<typeof GetUserByIdParamsSchema>;
export const BulkUpdateUsersParamsSchema = z.object({
users: z
.array(
z.object({
email: z.email().optional().describe("User email"),
userId: z
.string()
.optional()
.describe("User ID (alternative to email)"),
dataFields: z
.record(z.string(), z.any())
.optional()
.describe("User data fields to update"),
mergeNestedObjects: z
.boolean()
.optional()
.describe("Whether to merge nested objects"),
})
)
.describe("Array of users to update"),
});
export const DeleteUserByEmailParamsSchema = z.object({
email: z.email().describe("Email address of the user to delete"),
});
export type DeleteUserByEmailParams = z.infer<
typeof DeleteUserByEmailParamsSchema
>;
export const DeleteUserByUserIdParamsSchema = z.object({
userId: z.string().describe("User ID of the user to delete"),
});
export type DeleteUserByUserIdParams = z.infer<
typeof DeleteUserByUserIdParamsSchema
>;
export const UserEventsResponseSchema = z.object({
events: z.array(z.record(z.string(), z.any())),
});
export const SentMessageSchema = z.object({
messageId: z.string(),
campaignId: z.number(),
templateId: z.number().optional(),
campaignName: z.string().optional(),
templateName: z.string().optional(),
messageMedium: z.enum(["Email", "Push", "InApp", "SMS"]),
status: z.string(),
sentAt: FlexibleTimestampSchema, // API returns various formats
createdAt: FlexibleTimestampSchema.optional(), // API returns various formats
updatedAt: FlexibleTimestampSchema.optional(), // API returns various formats
dataFields: z.record(z.string(), z.any()).optional(),
});
export const GetSentMessagesResponseSchema = z.object({
messages: z.array(SentMessageSchema),
totalCount: z.number().optional(),
});
export const GetSentMessagesParamsSchema = z
.object({
email: z.email().optional().describe("User email address"),
userId: z.string().optional().describe("User ID (alternative to email)"),
limit: z
.number()
.min(1)
.max(1000)
.optional()
.describe(
"Maximum number of messages to return (default: 10, max: 1000)"
),
campaignIds: z
.array(z.number())
.optional()
.describe("Only include messages from these campaigns"),
startDateTime: IterableDateTimeSchema.optional().describe(
"Start date time (yyyy-MM-dd HH:mm:ss ZZ)"
),
endDateTime: IterableDateTimeSchema.optional().describe(
"End date time (yyyy-MM-dd HH:mm:ss ZZ)"
),
excludeBlastCampaigns: z
.boolean()
.optional()
.describe("Exclude results from blast campaigns"),
messageMedium: z
.enum(["Email", "Push", "InApp", "SMS"])
.optional()
.describe("Only include messages of this type"),
})
.refine(
(data) => data.email || data.userId,
"Either email or userId must be provided"
)
.describe("Parameters for getting messages sent to a user");
export const GetUserFieldsResponseSchema = z
.object({
fields: z.record(z.string(), z.string()), // Field names map to field types as strings
})
.passthrough();
export type GetUserFieldsResponse = z.infer<typeof GetUserFieldsResponseSchema>;
export type UserEvent = z.infer<typeof EventRecordSchema>;
export type SentMessage = z.infer<typeof SentMessageSchema>;
export type GetSentMessagesResponse = z.infer<
typeof GetSentMessagesResponseSchema
>;
export type GetSentMessagesParams = z.infer<typeof GetSentMessagesParamsSchema>;
export type BulkUpdateUsersParams = z.infer<typeof BulkUpdateUsersParamsSchema>;
/**
* Schema for updating user email address
* Only use with email-based projects. For userId/hybrid projects, use updateUser instead.
*/
export const UpdateEmailParamsSchema = z
.object({
currentEmail: z
.email()
.optional()
.describe(
"An email address that identifies a user profile in Iterable. Provide a currentEmail or a currentUserId (but not both), depending on how your project identifies users."
),
currentUserId: z
.string()
.optional()
.describe(
"A user ID that identifies a user profile in Iterable. Provide a currentEmail or a currentUserId (but not both), depending on how your project identifies users."
),
newEmail: z
.email()
.describe("The new email address to assign to the specified user."),
})
.refine(
(data) => data.currentEmail || data.currentUserId,
"Either currentEmail or currentUserId must be provided"
);
export type UpdateEmailParams = z.infer<typeof UpdateEmailParamsSchema>;
/**
* Schema for updating user subscriptions
* IMPORTANT: This endpoint overwrites (does not merge) existing data for any non-null fields specified.
*/
export const UpdateUserSubscriptionsParamsSchema = z
.object({
email: z
.email()
.optional()
.describe(
"An email address that identifies a user profile in Iterable. For each user in your request, provide an email or a userId (but not both), depending on how your project identifies users."
),
userId: z
.string()
.optional()
.describe(
"A user ID that identifies a user profile in Iterable. For each user in your request, provide an email or a userId (but not both), depending on how your project identifies users."
),
emailListIds: z
.array(z.number())
.optional()
.describe("Lists that a user is subscribed to"),
subscribedMessageTypeIds: z
.array(z.number())
.optional()
.describe(
"Individual message type IDs to subscribe (does not impact channel subscriptions). To set a value for this field, first have your CSM enable the opt-in message types feature. Otherwise, attempting to set this field causes an error."
),
unsubscribedChannelIds: z
.array(z.number())
.optional()
.describe("Email channel ids to unsubscribe from"),
unsubscribedMessageTypeIds: z
.array(z.number())
.optional()
.describe(
"Individual message type IDs to unsubscribe (does not impact channel subscriptions)."
),
campaignId: z
.number()
.optional()
.describe("Campaign to attribute unsubscribes"),
templateId: z
.number()
.optional()
.describe("Template to attribute unsubscribes"),
validateChannelAlignment: z
.boolean()
.optional()
.describe(
"Defaults to true (validation enabled). When false, allows subscribing users to message types that belong to unsubscribed channels. By default, Iterable validates that subscribed message types belong to subscribed channels. Setting this to false bypasses this validation, allowing you to save message type preferences even when the parent channel is unsubscribed. Users won't receive messages from these types while the channel remains unsubscribed, but their preferences are preserved for when the channel becomes subscribed."
),
})
.refine(
(data) => data.email || data.userId,
"Either email or userId must be provided"
);
export type UpdateUserSubscriptionsParams = z.infer<
typeof UpdateUserSubscriptionsParamsSchema
>;
export const ArrayMergeSchema = z.object({
field: z
.string()
.describe(
"Top-level user profile field containing an array to merge from source to destination"
),
dedupeBy: z
.string()
.optional()
.describe(
"Field on array objects used for de-duplication during merge (only for arrays of objects)"
),
});
export const MergeUsersParamsSchema = z
.object({
sourceEmail: z
.email()
.optional()
.describe("Email of the source user profile to merge from"),
sourceUserId: z
.string()
.optional()
.describe("User ID of the source user profile to merge from"),
destinationEmail: z
.email()
.optional()
.describe("Email of the destination user profile to merge into"),
destinationUserId: z
.string()
.optional()
.describe("User ID of the destination user profile to merge into"),
arrayMerge: z
.array(ArrayMergeSchema)
.optional()
.describe(
"Array fields whose contents should be merged (only custom arrays, not Iterable-managed ones like devices)"
),
})
.refine(
(data) => data.sourceEmail || data.sourceUserId,
"Either sourceEmail or sourceUserId must be provided"
)
.refine(
(data) => data.destinationEmail || data.destinationUserId,
"Either destinationEmail or destinationUserId must be provided"
);
export type MergeUsersParams = z.infer<typeof MergeUsersParamsSchema>;
export type ArrayMerge = z.infer<typeof ArrayMergeSchema>;