import {z} from 'zod' export type LastModifiedInfo = {time?: unknown | undefined}; export type ContentSourceMetaData = {charset?: string | undefined, fieldNames?: Array | undefined, rowNumber?: number | undefined, separator?: string | undefined}; export type ContentSource = {contentSourceName?: string | undefined, createInfo?: LastModifiedInfo | undefined, lastModifiedInfo?: LastModifiedInfo | undefined, metaData?: ContentSourceMetaData | undefined, resourceLink?: string | undefined, resourceType?: ('RESOURCE_TYPE_UNSPECIFIED' | 'RESOURCE_TYPE_GOOGLE_SPREADSHEET' | 'RESOURCE_TYPE_REMOTE_FILE') | undefined}; export type FeedField = {defaultValue?: string | undefined, filterable?: boolean | undefined, id?: number | undefined, name?: string | undefined, renderable?: boolean | undefined, required?: boolean | undefined, type?: ('TYPE_UNKNOWN' | 'STRING' | 'LONG' | 'GPA_SERVED_IMAGE_URL' | 'GPA_SERVED_ASSET_URL' | 'COUNTRY_CODE_ISO' | 'FLOAT' | 'CM360_KEYWORD' | 'CM360_SITE_ID' | 'BOOL' | 'EXIT_URL' | 'DATETIME' | 'CM360_CREATIVE_ID' | 'CM360_PLACEMENT_ID' | 'CM360_AD_ID' | 'CM360_ADVERTISER_ID' | 'CM360_CAMPAIGN_ID' | 'CITY' | 'REGION' | 'POSTAL_CODE' | 'METRO' | 'CUSTOM_VALUE' | 'REMARKETING_VALUE' | 'GEO_CANONICAL' | 'WEIGHT' | 'STRING_LIST' | 'CREATIVE_DIMENSION' | 'USERLIST_ID' | 'ASSET_LIBRARY_DIRECTORY_HANDLE' | 'ASSET_LIBRARY_VIDEO_HANDLE' | 'ASSET_LIBRARY_HANDLE' | 'THIRD_PARTY_SERVED_URL' | 'CM360_DYNAMIC_TARGETING_KEY' | 'DV360_LINE_ITEM_ID') | undefined}; export type Element = {activeFieldId?: number | undefined, createInfo?: LastModifiedInfo | undefined, defaultFieldId?: number | undefined, elementName?: string | undefined, endTimestampFieldId?: number | undefined, externalIdFieldId?: number | undefined, feedFields?: Array | undefined, isLocalTimestamp?: boolean | undefined, lastModifiedInfo?: LastModifiedInfo | undefined, proximityTargetingFieldId?: number | undefined, reportingLabelFieldId?: number | undefined, startTimestampFieldId?: number | undefined}; export type FieldError = {fieldId?: number | undefined, fieldName?: string | undefined, fieldValues?: Array | undefined, ingestionError?: ('UNKNOWN_PARSING_ERROR' | 'MISSING_ID' | 'MISSING_REPORTING_LABEL' | 'EMPTY_VALUE' | 'ASSET_DOWNLOAD_ERROR' | 'ID_TOO_LONG' | 'DUPLICATE_ID' | 'PARSING_ERROR' | 'COUNTRY_PARSING_ERROR' | 'LONG_PARSING_ERROR' | 'BOOL_PARSING_ERROR' | 'EXPANDED_URL_PARSING_ERROR' | 'FLOAT_PARSING_ERROR' | 'DATETIME_PARSING_ERROR' | 'INVALID_PREFERENCE_VALUE' | 'GEO_NOT_FOUND_ERROR' | 'GEO_PARSING_ERROR' | 'GEO_PROXIMITY_TARGETING_MULTIPLE_LOCATION_ERROR' | 'POSTAL_CODE_PARSING_ERROR' | 'METRO_CODE_PARSING_ERROR' | 'DATETIME_WITHOUT_TIMEZONE_PARSING_ERROR' | 'WEIGHT_PARSING_ERROR' | 'CREATIVE_DIMENSION_PARSING_ERROR' | 'MULTIVALUE_ID' | 'ENDTIME_BEFORE_STARTTIME' | 'INVALID_ASSET_LIBRARY_HANDLE' | 'INVALID_ASSET_LIBRARY_VIDEO_HANDLE' | 'INVALID_ASSET_LIBRARY_DIRECTORY_HANDLE' | 'DYNAMIC_TARGETING_KEY_NOT_DEFINED_FOR_ADVERTISER' | 'USERLIST_ID_NOT_ACCESSIBLE_FOR_ADVERTISER' | 'ENDTIME_PASSED' | 'ENDTIME_TOO_SOON' | 'TEXT_ASSET_REFERENCE' | 'IMAGE_ASSET_SCS_REFERENCE' | 'AIRPORT_GEO_TARGET' | 'CANONICAL_NAME_QUERY_MISMATCH' | 'NO_DEFAULT_ROW' | 'NO_ACTIVE_DEFAULT_ROW' | 'NO_DEFAULT_ROW_IN_DATE_RANGE' | 'NO_ACTIVE_DEFAULT_ROW_IN_DATE_RANGE' | 'PAYLOAD_LIMIT_EXCEEDED' | 'SSL_NOT_COMPLIANT') | undefined, isError?: boolean | undefined}; export type IngestionErrorRecord = {errors?: Array | undefined, recordId?: string | undefined}; export type IngestionStatus = {numActiveRows?: unknown | undefined, numRowsProcessed?: unknown | undefined, numRowsTotal?: unknown | undefined, numRowsWithErrors?: unknown | undefined, numWarningsTotal?: unknown | undefined}; export type FeedIngestionStatus = {ingestionErrorRecords?: Array | undefined, ingestionStatus?: IngestionStatus | undefined, state?: ('FEED_PROCESSING_STATE_UNKNOWN' | 'CANCELLED' | 'INGESTING_QUEUED' | 'INGESTING' | 'INGESTED_SUCCESS' | 'INGESTED_FAILURE' | 'REQUEST_TO_PUBLISH' | 'PUBLISHING' | 'PUBLISHED_SUCCESS' | 'PUBLISHED_FAILURE') | undefined}; export type FeedSchedule = {repeatValue?: unknown | undefined, scheduleEnabled?: boolean | undefined, startHour?: string | undefined, startMinute?: string | undefined, timeZone?: string | undefined}; export type DynamicFeed = {contentSource?: ContentSource | undefined, createInfo?: LastModifiedInfo | undefined, dynamicFeedId?: unknown | undefined, dynamicFeedName?: string | undefined, element?: Element | undefined, feedIngestionStatus?: FeedIngestionStatus | undefined, feedSchedule?: FeedSchedule | undefined, hasPublished?: boolean | undefined, lastModifiedInfo?: LastModifiedInfo | undefined, status?: ('STATUS_UNKNOWN' | 'ACTIVE' | 'INACTIVE' | 'DELETED') | undefined, studioAdvertiserId?: unknown | undefined}; export type UpdateApiStudioDynamicFeedsArgs = {body: DynamicFeed}; export type UpdateApiStudioDynamicFeedsOptions = {baseUrl?: string | undefined, Oauth2?: string | undefined, Oauth2c?: string | undefined, fetch?: typeof fetch | undefined}; export const lastModifiedInfo = z.object({time: z.string().optional()}); export const contentSourceMetaData = z.object({charset: z.string().optional(), fieldNames: z.array(z.string()).optional(), rowNumber: z.number().int().optional(), separator: z.string().optional()}); export const contentSource = z.object({contentSourceName: z.string().optional(), createInfo: lastModifiedInfo.optional(), lastModifiedInfo: lastModifiedInfo.optional(), metaData: contentSourceMetaData.optional(), resourceLink: z.string().optional(), resourceType: z.enum(["RESOURCE_TYPE_UNSPECIFIED", "RESOURCE_TYPE_GOOGLE_SPREADSHEET", "RESOURCE_TYPE_REMOTE_FILE"]).optional()}); export const feedField = z.object({defaultValue: z.string().optional(), filterable: z.boolean().optional(), id: z.number().int().optional(), name: z.string().optional(), renderable: z.boolean().optional(), required: z.boolean().optional(), type: z.enum(["TYPE_UNKNOWN", "STRING", "LONG", "GPA_SERVED_IMAGE_URL", "GPA_SERVED_ASSET_URL", "COUNTRY_CODE_ISO", "FLOAT", "CM360_KEYWORD", "CM360_SITE_ID", "BOOL", "EXIT_URL", "DATETIME", "CM360_CREATIVE_ID", "CM360_PLACEMENT_ID", "CM360_AD_ID", "CM360_ADVERTISER_ID", "CM360_CAMPAIGN_ID", "CITY", "REGION", "POSTAL_CODE", "METRO", "CUSTOM_VALUE", "REMARKETING_VALUE", "GEO_CANONICAL", "WEIGHT", "STRING_LIST", "CREATIVE_DIMENSION", "USERLIST_ID", "ASSET_LIBRARY_DIRECTORY_HANDLE", "ASSET_LIBRARY_VIDEO_HANDLE", "ASSET_LIBRARY_HANDLE", "THIRD_PARTY_SERVED_URL", "CM360_DYNAMIC_TARGETING_KEY", "DV360_LINE_ITEM_ID"]).optional()}); export const element = z.object({activeFieldId: z.number().int().optional(), createInfo: lastModifiedInfo.optional(), defaultFieldId: z.number().int().optional(), elementName: z.string().optional(), endTimestampFieldId: z.number().int().optional(), externalIdFieldId: z.number().int().optional(), feedFields: z.array(feedField).optional(), isLocalTimestamp: z.boolean().optional(), lastModifiedInfo: lastModifiedInfo.optional(), proximityTargetingFieldId: z.number().int().optional(), reportingLabelFieldId: z.number().int().optional(), startTimestampFieldId: z.number().int().optional()}); export const fieldError = z.object({fieldId: z.number().int().optional(), fieldName: z.string().optional(), fieldValues: z.array(z.string()).optional(), ingestionError: z.enum(["UNKNOWN_PARSING_ERROR", "MISSING_ID", "MISSING_REPORTING_LABEL", "EMPTY_VALUE", "ASSET_DOWNLOAD_ERROR", "ID_TOO_LONG", "DUPLICATE_ID", "PARSING_ERROR", "COUNTRY_PARSING_ERROR", "LONG_PARSING_ERROR", "BOOL_PARSING_ERROR", "EXPANDED_URL_PARSING_ERROR", "FLOAT_PARSING_ERROR", "DATETIME_PARSING_ERROR", "INVALID_PREFERENCE_VALUE", "GEO_NOT_FOUND_ERROR", "GEO_PARSING_ERROR", "GEO_PROXIMITY_TARGETING_MULTIPLE_LOCATION_ERROR", "POSTAL_CODE_PARSING_ERROR", "METRO_CODE_PARSING_ERROR", "DATETIME_WITHOUT_TIMEZONE_PARSING_ERROR", "WEIGHT_PARSING_ERROR", "CREATIVE_DIMENSION_PARSING_ERROR", "MULTIVALUE_ID", "ENDTIME_BEFORE_STARTTIME", "INVALID_ASSET_LIBRARY_HANDLE", "INVALID_ASSET_LIBRARY_VIDEO_HANDLE", "INVALID_ASSET_LIBRARY_DIRECTORY_HANDLE", "DYNAMIC_TARGETING_KEY_NOT_DEFINED_FOR_ADVERTISER", "USERLIST_ID_NOT_ACCESSIBLE_FOR_ADVERTISER", "ENDTIME_PASSED", "ENDTIME_TOO_SOON", "TEXT_ASSET_REFERENCE", "IMAGE_ASSET_SCS_REFERENCE", "AIRPORT_GEO_TARGET", "CANONICAL_NAME_QUERY_MISMATCH", "NO_DEFAULT_ROW", "NO_ACTIVE_DEFAULT_ROW", "NO_DEFAULT_ROW_IN_DATE_RANGE", "NO_ACTIVE_DEFAULT_ROW_IN_DATE_RANGE", "PAYLOAD_LIMIT_EXCEEDED", "SSL_NOT_COMPLIANT"]).optional(), isError: z.boolean().optional()}); export const ingestionErrorRecord = z.object({errors: z.array(fieldError).optional(), recordId: z.string().optional()}); export const ingestionStatus = z.object({numActiveRows: z.string().optional(), numRowsProcessed: z.string().optional(), numRowsTotal: z.string().optional(), numRowsWithErrors: z.string().optional(), numWarningsTotal: z.string().optional()}); export const feedIngestionStatus = z.object({ingestionErrorRecords: z.array(ingestionErrorRecord).optional(), ingestionStatus: ingestionStatus.optional(), state: z.enum(["FEED_PROCESSING_STATE_UNKNOWN", "CANCELLED", "INGESTING_QUEUED", "INGESTING", "INGESTED_SUCCESS", "INGESTED_FAILURE", "REQUEST_TO_PUBLISH", "PUBLISHING", "PUBLISHED_SUCCESS", "PUBLISHED_FAILURE"]).optional()}); export const feedSchedule = z.object({repeatValue: z.string().optional(), scheduleEnabled: z.boolean().optional(), startHour: z.string().optional(), startMinute: z.string().optional(), timeZone: z.string().optional()}); export const dynamicFeed = z.object({contentSource: contentSource.optional(), createInfo: lastModifiedInfo.optional(), dynamicFeedId: z.string().optional(), dynamicFeedName: z.string().optional(), element: element.optional(), feedIngestionStatus: feedIngestionStatus.optional(), feedSchedule: feedSchedule.optional(), hasPublished: z.boolean().optional(), lastModifiedInfo: lastModifiedInfo.optional(), status: z.enum(["STATUS_UNKNOWN", "ACTIVE", "INACTIVE", "DELETED"]).optional(), studioAdvertiserId: z.string().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 }; /** * Updates a new dynamic feed. For draft feeds, only Element can be updated. For published feeds, only FeedSchedule can be updated. Other fields will be ignored. * * PUT /studio/dynamicFeeds */ export const updateApiStudioDynamicFeeds = async (args: UpdateApiStudioDynamicFeedsArgs, options?: UpdateApiStudioDynamicFeedsOptions) => { const {baseUrl = "https://dfareporting.googleapis.com/dfareporting/v5", fetch: fetchFn = fetch, Oauth2, Oauth2c} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (Oauth2 !== undefined) headers.set('authorization', `Bearer ${Oauth2}`) if (Oauth2c !== undefined) headers.set('authorization', `Bearer ${Oauth2c}`) const url = `${baseUrl.replace(/\/+$/, '')}/studio/dynamicFeeds${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "PUT", 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(dynamicFeed, await res.json()) };