import {z} from 'zod' export type PostStatus = 'Tentative' | 'ToDo' | 'InProgress' | 'ForReview' | 'Blocked' | 'Finalized' | 'Scheduled' | 'Posted'; export type GetApiPostsArgs = {limit?: number | undefined, cursor?: string | undefined, ids?: (string | Array) | undefined, status?: PostStatus | undefined, channel?: ('LinkedIn' | 'Twitter' | 'Instagram' | 'TikTok' | 'YouTubeShorts') | undefined, linkedInProfileId?: string | undefined, xProfileId?: string | undefined, instagramProfileId?: string | undefined, tikTokProfileId?: string | undefined, youTubeProfileId?: string | undefined, labelIds?: (string | Array) | undefined, publishDateMin?: string | undefined, publishDateMax?: string | undefined, createdAtMin?: string | undefined, createdAtMax?: string | undefined, sortBy?: ('createdAt' | 'publishAt') | undefined, sortOrder?: ('asc' | 'desc') | undefined}; export type GetApiPostsOptions = {baseUrl?: string | undefined, bearerAuth?: string | undefined, fetch?: typeof fetch | undefined}; export const postStatus = z.enum(["Tentative", "ToDo", "InProgress", "ForReview", "Blocked", "Finalized", "Scheduled", "Posted"]); export const channelProfile = z.object({id: z.string().optional(), name: z.string().nullable().optional(), detail: z.string().nullable().optional()}); export const asset = z.object({id: z.string().optional(), name: z.string().optional(), url: z.string().optional(), mimetype: z.string().optional(), size: z.number().int().optional(), width: z.number().int().nullable().optional(), height: z.number().int().nullable().optional(), duration: z.number().nullable().optional()}); export const instagramAssetTag = z.object({username: z.string().optional(), x: z.number().nullable().optional(), y: z.number().nullable().optional()}); export const instagramAsset = z.object({id: z.string().optional(), name: z.string().optional(), url: z.string().optional(), mimetype: z.string().optional(), size: z.number().int().optional(), width: z.number().int().nullable().optional(), height: z.number().int().nullable().optional(), duration: z.number().nullable().optional(), tags: z.array(instagramAssetTag).optional()}); export const instagramLocation = z.object({pageId: z.string().optional(), name: z.string().optional()}); export const instagramFeedContent = z.object({profile: channelProfile.nullable().optional(), type: z.literal("Feed").optional(), copy: z.string().optional(), assets: z.array(instagramAsset).optional(), collaborators: z.array(z.string()).optional(), location: instagramLocation.nullable().optional()}); export const instagramReelContent = z.object({profile: channelProfile.nullable().optional(), type: z.literal("Reel").optional(), copy: z.string().optional(), assets: z.array(instagramAsset).optional(), coverPhoto: asset.nullable().optional(), shareToFeed: z.boolean().optional(), trialReelGraduationStrategy: z.enum(["MANUAL", "SS_PERFORMANCE"]).nullable().optional(), collaborators: z.array(z.string()).optional(), location: instagramLocation.nullable().optional()}); export const instagramStoryContent = z.object({profile: channelProfile.nullable().optional(), type: z.literal("Story").optional(), assets: z.array(instagramAsset).optional()}); export const instagramContent = z.discriminatedUnion("type", [instagramFeedContent, instagramReelContent, instagramStoryContent]).nullable(); export const tikTokPrivacyLevel = z.enum(["PUBLIC_TO_EVERYONE", "FOLLOWER_OF_CREATOR", "MUTUAL_FOLLOW_FRIENDS", "SELF_ONLY"]); export const tikTokContent = z.object({profile: channelProfile.nullable().optional(), copy: z.string().optional(), assets: z.array(asset).optional(), privacyLevel: tikTokPrivacyLevel.optional(), isCommentDisabled: z.boolean().optional(), isDuetDisabled: z.boolean().optional(), isStitchDisabled: z.boolean().optional(), isPromotingBusiness: z.boolean().optional(), isPaidPartnership: z.boolean().optional(), videoCoverTimestampMs: z.number().int().nullable().optional()}).nullable(); export const youTubePrivacyStatus = z.enum(["public", "private", "unlisted"]); export const youTubeShortsContent = z.object({profile: channelProfile.nullable().optional(), title: z.string().nullable().optional(), description: z.string().nullable().optional(), assets: z.array(asset).optional(), privacyStatus: youTubePrivacyStatus.optional(), categoryId: z.string().nullable().optional(), notifySubscribers: z.boolean().optional(), isEmbeddable: z.boolean().optional(), isSelfDeclaredMadeForKids: z.boolean().optional()}).nullable(); export const post = z.object({id: z.string().optional(), url: z.string().optional(), title: z.string().optional(), channels: z.array(z.string()).optional(), status: postStatus.optional(), publishDate: z.string().optional(), publishAt: z.string().nullable().optional(), createdAt: z.string().optional(), updatedAt: z.string().optional(), archivedAt: z.string().nullable().optional(), labels: z.array(z.object({id: z.string().optional(), name: z.string().optional(), color: z.string().optional(), backgroundColor: z.string().optional()})).optional(), linkedIn: z.object({profile: channelProfile.nullable().optional(), copy: z.string().optional(), assets: z.array(asset).optional()}).nullable().optional(), x: z.object({profile: channelProfile.nullable().optional(), tweets: z.array(z.object({copy: z.string().optional(), assets: z.array(asset).optional()})).optional()}).nullable().optional(), instagram: instagramContent.optional(), tikTok: tikTokContent.optional(), youTubeShorts: youTubeShortsContent.optional()}); export const getApiPostsResponse = z.object({posts: z.array(post).optional(), nextCursor: z.string().nullable().optional(), hasMore: 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 }; /** * List posts * * GET /posts */ export const getApiPosts = async (args: GetApiPostsArgs, options?: GetApiPostsOptions) => { const {baseUrl = "https://app.tryordinal.com/api/v1/company", fetch: fetchFn = fetch, bearerAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.limit != null) query.append("limit", String(args.limit)) if (args.cursor != null) query.append("cursor", String(args.cursor)) if (args.ids != null) query.append("ids", String(args.ids)) if (args.status != null) query.append("status", String(args.status)) if (args.channel != null) query.append("channel", String(args.channel)) if (args.linkedInProfileId != null) query.append("linkedInProfileId", String(args.linkedInProfileId)) if (args.xProfileId != null) query.append("xProfileId", String(args.xProfileId)) if (args.instagramProfileId != null) query.append("instagramProfileId", String(args.instagramProfileId)) if (args.tikTokProfileId != null) query.append("tikTokProfileId", String(args.tikTokProfileId)) if (args.youTubeProfileId != null) query.append("youTubeProfileId", String(args.youTubeProfileId)) if (args.labelIds != null) query.append("labelIds", String(args.labelIds)) if (args.publishDateMin != null) query.append("publishDateMin", String(args.publishDateMin)) if (args.publishDateMax != null) query.append("publishDateMax", String(args.publishDateMax)) if (args.createdAtMin != null) query.append("createdAtMin", String(args.createdAtMin)) if (args.createdAtMax != null) query.append("createdAtMax", String(args.createdAtMax)) if (args.sortBy != null) query.append("sortBy", String(args.sortBy)) if (args.sortOrder != null) query.append("sortOrder", String(args.sortOrder)) if (bearerAuth !== undefined) headers.set('authorization', `Bearer ${bearerAuth}`) const url = `${baseUrl.replace(/\/+$/, '')}/posts${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(getApiPostsResponse, await res.json()) };