import {z} from 'zod' export type GetApiApiChannelsArgs = {limit?: number | undefined}; export type GetApiApiChannelsOptions = {baseUrl?: string | undefined, basicAuth?: {username: string, password: string} | undefined, fetch?: typeof fetch | undefined}; export const attributes = z.object({account_creation: z.string().optional(), advertising_id: z.string().optional(), age: z.number().int().optional(), altitude: z.number().optional(), birthdate: z.string().optional(), city: z.string().optional(), company: z.string().optional(), country: z.string().optional(), email: z.string().optional(), first_name: z.string().optional(), full_name: z.string().optional(), gender: z.string().optional(), home_phone: z.number().int().optional(), last_name: z.string().optional(), latitude: z.number().optional(), longitude: z.number().optional(), loyalty_tier: z.string().optional(), mobile_phone: z.number().int().optional(), region: z.string().optional(), title: z.string().optional(), username: z.string().optional(), work_phone: z.number().int().optional(), zipcode: z.number().int().optional()}).and(z.record(z.string(), z.union([z.string(), z.number(), z.number().int()]))); export const commercialOptedIn = z.string(); export const commercialOptedOut = z.string(); export const deviceAttributes = z.object({ua_app_version: z.string().optional(), ua_browser_name: z.string().optional(), ua_browser_type: z.enum(["mobile", "desktop"]).optional(), ua_browser_version: z.string().optional(), ua_carrier: z.string().optional(), ua_country: z.string().optional(), ua_country_code: z.string().optional(), ua_device_model: z.string().optional(), ua_device_os: z.string().optional(), ua_email_domain: z.string().optional(), ua_language: z.string().optional(), ua_local_tz: z.string().optional(), ua_location_settings: z.enum(["true", "false"]).optional(), ua_ndc: z.string().optional(), ua_rcs_enabled: z.literal("true").optional(), ua_sdk_version: z.string().optional(), ua_subdivision: z.string().optional()}); export const iOSChannelObject = z.object({badge: z.number().int().optional(), quiettime: z.object({end: z.string().nullable().optional(), start: z.string().nullable().optional()}).optional(), scheduled_summary: z.boolean().optional(), time_sensitive: z.boolean().optional(), tz: z.string().nullable().optional()}); export const openChannelOptionsObject = z.object({identifiers: z.record(z.string(), z.unknown()).optional(), old_address: z.string().optional(), open_platform_name: z.string()}); export const subscriptionListMutation = z.enum(["subscribe", "unsubscribe"]); export const subscriptionListId = z.string().min(1).max(32); export const scopes = z.enum(["app", "web", "email", "sms"]); export const subscriptionListAction = z.union([z.object({action: subscriptionListMutation, list_id: subscriptionListId, type: z.literal("channel")}), z.object({action: subscriptionListMutation, list_id: subscriptionListId, scope: scopes, type: z.literal("contact")})]); export const subscriptionListObject = z.object({action: subscriptionListAction, list_id: subscriptionListId, timestamp: z.string().optional()}); export const suppressionState = z.enum(["spam_complaint", "commercial_spam_complaint", "bounce", "imported", "carrier_deactivation"]); export const tagArray = z.array(z.string().min(1).max(128)); export const tagGroupObject = z.record(z.string(), tagArray); export const tagArrayBig = z.array(z.string().min(1).max(128)); export const transactionalOptedIn = z.string(); export const transactionalOptedOut = z.string(); export const channelListingObject = z.object({address: z.string().optional(), attributes: attributes.optional(), background: z.boolean().optional(), channel_id: z.string().optional(), commercial_opted_in: commercialOptedIn.optional(), commercial_opted_out: commercialOptedOut.optional(), created: z.string().optional(), device_attributes: deviceAttributes.optional(), device_type: z.enum(["ios", "android", "amazon", "web", "open", "email", "sms"]).optional(), email_address: z.string().optional(), installed: z.boolean().optional(), ios: iOSChannelObject.optional(), last_registration: z.string().nullable().optional(), msisdn: z.string().max(15).optional(), named_user_id: z.string().min(1).max(128).nullable().optional(), open: openChannelOptionsObject.optional(), opt_in: z.boolean().optional(), opt_in_date: z.string().optional(), opt_out_date: z.string().optional(), push_address: z.string().nullable().optional(), subscription_lists: z.array(subscriptionListObject).optional(), suppression_state: suppressionState.optional(), tag_groups: tagGroupObject.optional(), tags: tagArrayBig.optional(), transactional_opted_in: transactionalOptedIn.optional(), transactional_opted_out: transactionalOptedOut.optional(), web: z.object({subscription: z.object({keys: z.object({auth: z.string().optional(), p256dh: z.string().optional()}).optional()}).optional(), user_agent_string: z.string().optional()}).optional()}); export const getApiApiChannelsResponse = z.object({channels: z.array(channelListingObject).optional(), next_page: z.string().optional(), ok: z.boolean().optional()}); 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 }; /** * Channel listing * * GET /api/channels * * Also accepts auth: bearerAuth, oauth2Token */ export const getApiApiChannels = async (args: GetApiApiChannelsArgs, options?: GetApiApiChannelsOptions) => { const {baseUrl = "https://go.urbanairship.com", fetch: fetchFn = fetch, basicAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/vnd.urbanairship+json; version=3") if (args.limit != null) query.append("limit", String(args.limit)) if (basicAuth !== undefined) headers.set('authorization', `Basic ${btoa(`${basicAuth.username}:${basicAuth.password}`)}`) const url = `${baseUrl.replace(/\/+$/, '')}/api/channels${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(getApiApiChannelsResponse, await res.json()) };