import {z} from 'zod' export type CampaignSearchFields = {channels?: (Array<'PUSH' | 'EMAIL' | 'SMS'>) | undefined, created_by?: Array | undefined, created_date?: ({from_date?: string | undefined, to_date?: string | undefined}) | undefined, delivery_type?: (Array<'ONE_TIME' | 'PERIODIC' | 'EVENT_TRIGGERED' | 'BUSINESS_EVENT_TRIGGERED' | 'DEVICE_TRIGGERED' | 'LOCATION_TRIGGERED' | 'BROADCAST_LIVE_ACTIVITY'>) | undefined, id?: string | undefined, name?: string | undefined, status?: (Array<'ACTIVE' | 'SCHEDULED' | 'PAUSED' | 'SENT' | 'STOPPED' | 'ARCHIVED'>) | undefined, tags?: Array | undefined}; export type CampaignSearchRequest = {request_id: string, campaign_fields?: CampaignSearchFields | undefined, include_child_campaigns?: boolean | undefined, include_archive_campaigns?: boolean | undefined, limit: number, page: number}; export type CreateApiCampaignsSearchArgs = {'MOE-APPKEY': string, body: CampaignSearchRequest}; export type CreateApiCampaignsSearchOptions = {baseUrl?: string | undefined, BasicAuth?: {username: string, password: string} | undefined, fetch?: typeof fetch | undefined}; export const userAttributeFilter = z.object({filter_type: z.literal("user_attributes"), data_type: z.enum(["string", "double", "datetime", "bool"]), category: z.string().optional(), name: z.string(), operator: z.string(), value: z.unknown(), case_sensitive: z.boolean().optional(), negate: z.boolean().optional(), project_name: z.string().optional()}); export const actionFilter = z.object({filter_type: z.literal("actions"), action_name: z.string(), execution: z.object({type: z.enum(["atleast", "atmost", "exactly"]).optional(), count: z.number().int().optional()}).optional(), executed: z.boolean().optional(), attributes: z.lazy(() => filterGroup.optional()), condition: z.string().optional()}); export const customSegmentFilter = z.object({filter_type: z.literal("custom_segments"), name: z.string().optional(), id: z.string()}); export const filterGroup: z.ZodType = z.object({filter_operator: z.enum(["and", "or"]), filters: z.array(z.union([userAttributeFilter, actionFilter, customSegmentFilter]))}); export const segmentationDetailsResponse = z.object({included_filters: filterGroup.optional(), excluded_filters: filterGroup.optional(), is_all_user_campaign: z.boolean().optional(), send_campaign_to_opt_out_users: z.boolean().optional()}); export const periodicDetails = z.object({sending_frequency: z.enum(["DAILY", "WEEKLY", "MONTHLY"]).optional(), repeat_frequency: z.number().int().optional(), no_of_occurences: z.number().int().optional(), repeat_on_date_of_month: z.array(z.number().int()).optional(), repeat_on_days_of_week: z.array(z.enum(["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"])).optional(), repeat_on_days_of_week_for_month: z.array(z.object({week_granularity: z.enum(["FIRST", "SECOND", "THIRD", "FOURTH", "LAST"]).optional(), repeat_on_days_of_week: z.array(z.enum(["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"])).optional()})).optional()}); export const bTSDetails = z.object({send_in_bts: z.boolean().optional(), if_user_bts_is_not_available: z.string().optional(), if_user_bts_outside_time_window: z.string().optional(), window_end_time: z.string().optional()}); export const userTimezoneDetails = z.object({send_in_user_timezone: z.boolean().optional(), send_if_user_timezone_has_passed: z.boolean().optional()}); export const schedulingDetails = z.object({delivery_type: z.enum(["ASAP", "AT_FIXED_TIME", "SEND_IN_BTS", "SEND_IN_USER_TIMEZONE"]), start_time: z.string().optional(), expiry_time: z.string().optional(), periodic_details: periodicDetails.optional(), bts_details: bTSDetails.optional(), user_timezone_details: userTimezoneDetails.optional()}); export const goalEventAttribute = z.object({name: z.string().optional(), condition: z.string().optional(), data_type: z.enum(["STRING", "DOUBLE", "BOOL", "NUMBER", "GEOPOINT", "DATETIME", "ARRAY_DOUBLE", "ARRAY_STRING", "OBJECT", "ARRAY_OBJECT"]).optional(), value: z.string().optional(), value1: z.string().optional(), negate: z.boolean().optional(), value_type: z.string().optional(), array_filter_type: z.string().optional(), filters: z.array(z.object({})).optional(), is_case_sensitive: z.boolean().optional()}); export const goal = z.object({goal_name: z.string().optional(), goal_event_name: z.string().optional(), goal_event_attribute: goalEventAttribute.optional(), is_primary_goal: z.boolean().optional(), revenue_attribute: z.string().optional(), revenue_currency: z.string().optional()}); export const conversionGoalDetails = z.object({attribution_window_in_hours: z.number().int().optional(), goals: z.array(goal).optional()}); export const controlGroupDetails = z.object({is_campaign_control_group_enabled: z.boolean().optional(), campaign_control_group_percentage: z.number().int().gte(0).lte(100).optional(), is_global_control_group_enabled: z.boolean().optional()}); export const uTMParams = z.object({utm_source: z.string(), utm_medium: z.string(), utm_campaign: z.string().optional(), utm_term: z.string().optional(), utm_content: z.string().optional(), utm_custom: z.string().optional()}); export const campaignAudienceLimit = z.object({limit: z.number().int().optional(), metrics: z.string().optional(), frequency: z.string().optional()}); export const campaignDetailsResponse = z.object({campaign_id: z.string().optional(), status: z.enum(["ACTIVE", "SCHEDULED", "PAUSED", "SENT", "STOPPED", "ARCHIVED"]).optional(), channel: z.enum(["PUSH", "EMAIL", "SMS"]).optional(), campaign_delivery_type: z.enum(["ONE_TIME", "PERIODIC", "EVENT_TRIGGERED", "BUSINESS_EVENT_TRIGGERED", "DEVICE_TRIGGERED", "LOCATION_TRIGGERED", "BROADCAST_LIVE_ACTIVITY"]).optional(), created_by: z.string().optional(), updated_by: z.string().optional(), created_at: z.string().optional(), updated_at: z.string().optional(), sent_time: z.string().optional(), flow_id: z.string().optional(), flow_name: z.string().optional(), parent_id: z.string().optional(), basic_details: z.object({}).optional(), campaign_content: z.object({}).optional(), trigger_condition: z.object({}).optional(), segmentation_details: segmentationDetailsResponse.optional(), scheduling_details: schedulingDetails.optional(), delivery_controls: z.object({}).optional(), advanced: z.object({}).optional(), conversion_goal_details: conversionGoalDetails.optional(), control_group_details: controlGroupDetails.optional(), utm_params: uTMParams.optional(), connector: z.object({connector_type: z.string().optional(), connector_name: z.string().optional()}).optional(), sender_name: z.string().optional(), campaign_audience_limit: campaignAudienceLimit.optional()}); export const createApiCampaignsSearchResponse = z.array(campaignDetailsResponse); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Search Campaigns * * POST /campaigns/search */ export const createApiCampaignsSearch = async (args: CreateApiCampaignsSearchArgs, options?: CreateApiCampaignsSearchOptions) => { const {baseUrl = "https://api-01.moengage.com/core-services/v1", fetch: fetchFn = fetch, BasicAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (args['MOE-APPKEY'] != null) headers.set("MOE-APPKEY", String(args['MOE-APPKEY'])) if (BasicAuth !== undefined) headers.set('authorization', `Basic ${btoa(`${BasicAuth.username}:${BasicAuth.password}`)}`) const url = `${baseUrl.replace(/\/+$/, '')}/campaigns/search${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "POST", headers, body: JSON.stringify(args.body)}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(createApiCampaignsSearchResponse, await res.json()) };