import {z} from 'zod' export type ResourceId = string; export type AudioDefinitionParameters = {pid?: (number | null) | undefined, language?: (string | null) | undefined}; export type CaptionDefinitionParameters = {name?: string | undefined, language?: string | undefined, type?: ('TELETEXT' | 'CEA608708') | undefined, page_number?: number | undefined}; export type AdditionalUrlOutput = {title?: string | undefined, url?: string | undefined, key?: string | undefined}; export type LiveStreamOptionsParameters = {ingest_format?: ('hls_pull' | 'rtmp' | 'rtp' | 'rtp_fec' | 'srt' | 'srt_pull' | 'zixi_push' | null) | undefined, enable_drm?: (boolean | null) | undefined, stream_type?: ('24/7' | 'event' | null) | undefined, stream_start?: (string | null) | undefined, stream_end?: (string | null) | undefined, stream_warmup?: number | undefined, dvr_window?: (30 | 3600 | 7200 | 10800 | 14400 | 18000 | 21600 | 25200 | 28800 | 32400 | 36000 | 39600 | 43200 | 46800 | 50400 | 54000 | 57600 | 61200 | 64800 | 68400 | 72000 | 75600 | 79200 | 82800 | 86400) | undefined, enable_live_to_vod?: boolean | undefined, live_to_vod_method?: ('hosted_capture' | 'renditions_capture' | null) | undefined, audio_definitions?: (Array | null) | undefined, caption_definitions?: (Array | null) | undefined, use_legacy_ott_params?: boolean | undefined, source_url?: (string | null) | undefined, mpd_profile?: ('dvb-dash' | 'mpeg-dash' | null) | undefined, clipping_window?: ('4h' | '6h' | '12h' | '24h' | '36h') | undefined, additional_outputs?: (Array | null) | undefined, purge_preview_content?: boolean | undefined}; export type Language = 'aa' | 'ab' | 'ae' | 'af' | 'ak' | 'am' | 'an' | 'ar' | 'as' | 'av' | 'ay' | 'az' | 'ba' | 'be' | 'bg' | 'bh' | 'bi' | 'bm' | 'bn' | 'bo' | 'br' | 'bs' | 'ca' | 'ce' | 'ch' | 'co' | 'cr' | 'cs' | 'cu' | 'cv' | 'cy' | 'da' | 'de' | 'dv' | 'dz' | 'ee' | 'el' | 'en' | 'eo' | 'es' | 'et' | 'eu' | 'fa' | 'ff' | 'fi' | 'fj' | 'fo' | 'fr' | 'fy' | 'ga' | 'gd' | 'gl' | 'gn' | 'gu' | 'gv' | 'ha' | 'he' | 'hi' | 'ho' | 'hr' | 'ht' | 'hu' | 'hy' | 'hz' | 'ia' | 'id' | 'ie' | 'ig' | 'ii' | 'ik' | 'io' | 'is' | 'it' | 'iu' | 'ja' | 'jv' | 'ka' | 'kg' | 'ki' | 'kj' | 'kk' | 'kl' | 'km' | 'kn' | 'ko' | 'kr' | 'ks' | 'ku' | 'kv' | 'kw' | 'ky' | 'la' | 'lb' | 'lg' | 'li' | 'ln' | 'lo' | 'lt' | 'lu' | 'lv' | 'mg' | 'mh' | 'mi' | 'mk' | 'ml' | 'mn' | 'mr' | 'ms' | 'mt' | 'my' | 'na' | 'nb' | 'nd' | 'ne' | 'ng' | 'nl' | 'nn' | 'no' | 'nr' | 'nv' | 'ny' | 'oc' | 'oj' | 'om' | 'or' | 'os' | 'pa' | 'pi' | 'pl' | 'ps' | 'pt' | 'qu' | 'rm' | 'rn' | 'ro' | 'ru' | 'rw' | 'sa' | 'sc' | 'sd' | 'se' | 'sg' | 'si' | 'sk' | 'sl' | 'sm' | 'sn' | 'so' | 'sq' | 'sr' | 'ss' | 'st' | 'su' | 'sv' | 'sw' | 'ta' | 'te' | 'tg' | 'th' | 'ti' | 'tk' | 'tl' | 'tn' | 'to' | 'tr' | 'ts' | 'tt' | 'tw' | 'ty' | 'ug' | 'uk' | 'ur' | 'uz' | 've' | 'vi' | 'vo' | 'wa' | 'wo' | 'xh' | 'yi' | 'yo' | 'za' | 'zh' | 'zu'; export type CustomParamSchema = {[key: string]: string}; export type MediaResourceCreateMetadata = {title?: string | undefined, description?: string | undefined, author?: string | undefined, drm?: boolean | undefined, permalink?: string | undefined, category?: ('Automotive' | 'Books and Literature' | 'Business and Finance' | 'Careers' | 'Education' | 'Events and Attractions' | 'Family and Relationships' | 'Fine Art' | 'Food & Drink' | 'Healthy Living' | 'Hobbies & Interests' | 'Home & Garden' | 'Medical Health' | 'Movies' | 'Music and Audio' | 'News and Politics' | 'Personal Finance' | 'Pets' | 'Pop Culture' | 'Real Estate' | 'Religion & Spirituality' | 'Science' | 'Shopping' | 'Sports' | 'Style & Fashion' | 'Technology & Computing' | 'Television' | 'Travel' | 'Video Gaming') | undefined, publish_start_date?: string | undefined, publish_end_date?: string | undefined, tags?: Array | undefined, language?: Language | undefined, custom_params?: CustomParamSchema | undefined, external_id?: string | undefined, duration?: number | undefined}; export type RelationshipWrite = {id: ResourceId}; export type SsaiConfig = {ad_schedule_id?: (string | null) | undefined, live_preroll?: boolean | undefined}; export type StreamRequestParameters = {region: 'eu-west-1' | 'us-east-1', options?: LiveStreamOptionsParameters | undefined, metadata?: MediaResourceCreateMetadata | undefined, relationships?: ({ingest_point?: RelationshipWrite | undefined, protection_rule?: RelationshipWrite | undefined, stream_config?: RelationshipWrite | undefined}) | undefined, ssai_config?: SsaiConfig | undefined}; export type CreateApiV2SitesSiteIdLiveBroadcastStreamsArgs = {site_id: ResourceId, body: StreamRequestParameters}; export type CreateApiV2SitesSiteIdLiveBroadcastStreamsOptions = {baseUrl?: string | undefined, v2ApiSecret?: string | undefined, fetch?: typeof fetch | undefined}; export const resourceId = z.string().min(8).max(8); export const relationshipRead = z.object({id: resourceId.optional(), type: z.string().optional()}); export const ingestEndpoint = z.object({url: z.string().nullable().optional(), key: z.string().nullable().optional()}); export const liveStreamPlayout = z.object({hls: z.string().nullable().optional(), dash: z.string().nullable().optional(), availability: z.enum(["not_available", "preview", "available"]).optional()}); export const liveStreamMetadata = z.object({status: z.enum(["capturing", "captured", "creating", "deleting", "destroying", "failed", "idle", "ready", "requested", "scheduled", "starting", "stopped", "stopping", "streaming"]).optional(), ingest: z.record(z.string(), z.record(z.string(), ingestEndpoint)).nullable().optional(), playout: liveStreamPlayout.optional(), title: z.string().nullable().optional(), drm: z.boolean().optional(), stream_start: z.string().nullable().optional(), stream_end: z.string().nullable().optional()}); export const audioDefinition = z.object({pid: z.number().int().nullable().optional(), language: z.string().nullable().optional()}); export const captionDefinition = z.object({name: z.string().optional(), language: z.string().optional(), type: z.object({}).optional()}); export const liveStreamObjectSchema = z.object({schema: z.string().optional(), id: z.string().min(8).max(8).nullable().optional(), created: z.string().nullable().optional(), last_modified: z.string().nullable().optional(), type: z.string().nullable().optional(), relationships: z.record(z.string(), relationshipRead).nullable().optional(), metadata: liveStreamMetadata.optional(), stream_type: z.enum(["24/7", "event"]).nullable().optional(), profile_name: z.string().nullable().optional(), cluster_region: z.string().nullable().optional(), ingest_format: z.enum(["hls_pull", "rtmp", "rtp", "rtp_fec", "srt", "srt_pull", "zixi_push"]).nullable().optional(), dvr_window: z.union([z.literal(30), z.literal(3600), z.literal(7200), z.literal(10800), z.literal(14400), z.literal(18000), z.literal(21600), z.literal(25200), z.literal(28800), z.literal(32400), z.literal(36000), z.literal(39600), z.literal(43200), z.literal(46800), z.literal(50400), z.literal(54000), z.literal(57600), z.literal(61200), z.literal(64800), z.literal(68400), z.literal(72000), z.literal(75600), z.literal(79200), z.literal(82800), z.literal(86400)]).optional(), audio_definitions: z.array(audioDefinition).nullable().optional(), caption_definitions: z.array(captionDefinition).nullable().optional(), use_legacy_ott_params: z.boolean().optional(), enable_live_to_vod: z.boolean().optional(), live_to_vod_method: z.enum(["hosted_capture", "renditions_capture"]).optional(), mpd_profile: z.string().nullable().optional(), stream_warmup: z.number().int().nullable().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 }; /** * Create a live stream * * POST /v2/sites/{site_id}/live/broadcast/streams/ */ export const createApiV2SitesSiteIdLiveBroadcastStreams = async (args: CreateApiV2SitesSiteIdLiveBroadcastStreamsArgs, options?: CreateApiV2SitesSiteIdLiveBroadcastStreamsOptions) => { const {baseUrl = "https://api.jwplayer.com", fetch: fetchFn = fetch, v2ApiSecret} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (v2ApiSecret !== undefined) headers.set("Authorization", v2ApiSecret) const url = `${baseUrl.replace(/\/+$/, '')}/v2/sites/${encodeURIComponent(String(args.site_id))}/live/broadcast/streams/${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(liveStreamObjectSchema, await res.json()) };