import {z} from 'zod' export type Schema0 = number | {curve: string} | {time: 'seconds'} | {args: Array, op: 'add' | 'subtract' | 'multiply' | 'divide' | 'min' | 'max' | 'abs' | 'negate' | 'sin' | 'cos' | 'pow' | 'sqrt' | 'floor' | 'round' | 'mod' | 'mix' | 'clamp' | 'step' | 'smoothstep'} | {axis: 'x' | 'y', project: {camera: {aimX: Schema0, aimY: Schema0, focal?: number | undefined, roll?: Schema0 | undefined, tiltX?: Schema0 | undefined, tiltY?: Schema0 | undefined, zoom: Schema0}, point: {x: Schema0, y: Schema0}}}; export type MotionCommandSetCurve = {name: string, type: 'setCurve', value: number | Array<{at: number, easing?: ('linear' | 'hold' | 'ease' | 'easeIn' | 'easeOut') | undefined, value: number}> | Schema0 | null}; export type MotionCommandBindProperty = {node: string, property: string, text?: ({decimals?: number | undefined, prefix?: string | undefined, suffix?: string | undefined}) | undefined, to: Schema0, type: 'bindProperty'}; export type MotionCommandSplit = {at: number, newNodeId?: string | undefined, node: string, type: 'split'}; export type MotionCommandTrim = {end?: number | undefined, node: string, ripple?: boolean | undefined, start?: number | undefined, type: 'trim'}; export type MotionCommandDelete = {node: string, ripple?: boolean | undefined, type: 'delete'}; export type MotionCommandDuplicate = {newNodeId?: string | undefined, node: string, type: 'duplicate'}; export type MotionCommandSetSpeed = {node: string, speed: number, type: 'setSpeed'}; export type MotionCommandSetTransition = {duration?: number | undefined, kind: 'none' | 'crossfade' | 'left' | 'right' | 'up' | 'down', node: string, type: 'setTransition'}; export type MotionCommandAddTitle = {align?: ('left' | 'center' | 'right') | undefined, box?: {width: number, x: number, y: number} | undefined, color?: string | undefined, duration?: number | undefined, font?: string | undefined, fontSize?: number | undefined, letterSpacing?: number | undefined, lineHeight?: number | undefined, nodeId?: string | undefined, parent?: string | undefined, start: number, text?: string | undefined, type: 'addTitle', weight?: number | undefined}; export type MotionCommandAddShape = {box?: {height: number, width: number, x: number, y: number} | undefined, color?: string | undefined, duration?: number | undefined, nodeId?: string | undefined, parent?: string | undefined, radius?: number | undefined, shape?: ('fill' | 'rect' | 'circle') | undefined, start: number, type: 'addShape'}; export type MotionCommandAddMedia = {duration?: number | undefined, mediaId?: string | undefined, nodeId?: string | undefined, parent?: string | undefined, ripple?: boolean | undefined, sourceId?: string | undefined, start: number, type: 'addMedia'}; export type MotionCommandSetTitle = {align?: ('left' | 'center' | 'right') | undefined, box?: {width: number, x: number, y: number} | undefined, color?: string | undefined, font?: string | undefined, fontSize?: number | undefined, letterSpacing?: number | undefined, lineHeight?: number | undefined, node: string, text?: string | undefined, type: 'setTitle', weight?: number | undefined}; export type MotionCommandSetShape = {box?: {height: number, width: number, x: number, y: number} | undefined, color?: string | undefined, node: string, radius?: number | undefined, shape?: ('fill' | 'rect' | 'circle') | undefined, type: 'setShape'}; export type MotionCommandAnimate = {in?: ({duration: number, easing?: ('linear' | 'hold' | 'easyEase' | 'easyEaseIn' | 'easyEaseOut' | 'autoBezier' | 'easeInOutSine' | 'easeInOutCubic' | 'easeInOutExpo' | 'easeOutCubic' | 'easeInCubic' | 'easeOutBack' | 'easeInOutBack' | 'springGentle' | 'springBouncy' | {x1: number, x2: number, y1: number, y2: number} | {inInfluence?: number | undefined, outInfluence?: number | undefined, speed?: number | undefined}) | undefined, kind: 'fade' | 'slideLeft' | 'slideRight' | 'slideUp' | 'slideDown' | 'pop'}) | undefined, node: string, out?: ({duration: number, easing?: ('linear' | 'hold' | 'easyEase' | 'easyEaseIn' | 'easyEaseOut' | 'autoBezier' | 'easeInOutSine' | 'easeInOutCubic' | 'easeInOutExpo' | 'easeOutCubic' | 'easeInCubic' | 'easeOutBack' | 'easeInOutBack' | 'springGentle' | 'springBouncy' | {x1: number, x2: number, y1: number, y2: number} | {inInfluence?: number | undefined, outInfluence?: number | undefined, speed?: number | undefined}) | undefined, kind: 'fade' | 'slideLeft' | 'slideRight' | 'slideUp' | 'slideDown' | 'pop'}) | undefined, type: 'animate'}; export type MotionCommandSetProperty = {at?: number | undefined, node: string, property: string, type: 'setProperty', value?: (number | string | boolean | 'normal' | 'clear' | 'src' | 'dst' | 'srcOver' | 'dstOver' | 'srcIn' | 'dstIn' | 'srcOut' | 'dstOut' | 'srcATop' | 'dstATop' | 'xor' | 'plus' | 'modulate' | 'screen' | 'overlay' | 'darken' | 'lighten' | 'colorDodge' | 'colorBurn' | 'hardLight' | 'softLight' | 'difference' | 'exclusion' | 'multiply' | 'hue' | 'saturation' | 'color' | 'luminosity' | 'linearBurn' | 'vividLight' | 'linearLight' | 'pinLight' | 'hardMix' | 'subtract' | 'divide' | 'darkerColor' | 'lighterColor' | 'stencilAlpha' | 'stencilLuma' | 'silhouetteAlpha' | 'silhouetteLuma' | 'dissolve' | 'animatedDissolve' | 'premultipliedColorBurn' | 'premultipliedColorDodge' | 'premultipliedDifference' | 'alphaAdd') | undefined}; export type MotionCommandSetKeyframes = {easing?: ('linear' | 'hold' | 'easyEase' | 'easyEaseIn' | 'easyEaseOut' | 'autoBezier' | 'easeInOutSine' | 'easeInOutCubic' | 'easeInOutExpo' | 'easeOutCubic' | 'easeInCubic' | 'easeOutBack' | 'easeInOutBack' | 'springGentle' | 'springBouncy' | {x1: number, x2: number, y1: number, y2: number} | {inInfluence?: number | undefined, outInfluence?: number | undefined, speed?: number | undefined} | 'continuous') | undefined, keys: Array<{at: number, easing?: ('linear' | 'hold' | 'easyEase' | 'easyEaseIn' | 'easyEaseOut' | 'autoBezier' | 'easeInOutSine' | 'easeInOutCubic' | 'easeInOutExpo' | 'easeOutCubic' | 'easeInCubic' | 'easeOutBack' | 'easeInOutBack' | 'springGentle' | 'springBouncy' | {x1: number, x2: number, y1: number, y2: number} | {inInfluence?: number | undefined, outInfluence?: number | undefined, speed?: number | undefined} | 'continuous') | undefined, value: number | string}>, node: string, property: string, type: 'setKeyframes'}; export type MotionCommandEditKeyframe = {at?: number | undefined, easing?: ('linear' | 'hold' | 'easyEase' | 'easyEaseIn' | 'easyEaseOut' | 'autoBezier' | 'easeInOutSine' | 'easeInOutCubic' | 'easeInOutExpo' | 'easeOutCubic' | 'easeInCubic' | 'easeOutBack' | 'easeInOutBack' | 'springGentle' | 'springBouncy' | {x1: number, x2: number, y1: number, y2: number} | {inInfluence?: number | undefined, outInfluence?: number | undefined, speed?: number | undefined}) | undefined, key?: string | undefined, keys?: Array | undefined, node: string, property: string, type: 'editKeyframe', value?: (number | string) | undefined}; export type MotionCommandRemoveKeyframes = {at?: Array | undefined, keys?: Array | undefined, node: string, property: string, type: 'removeKeyframes'}; export type MotionCommandAddEffect = {backdrop?: boolean | undefined, effectId?: string | undefined, index?: number | undefined, inputs?: {[key: string]: string} | undefined, kind: string, node: string, params?: ({[key: string]: number | string | boolean | Array | Array> | {x: number, y: number}}) | undefined, preset?: string | undefined, source?: string | undefined, type: 'addEffect', uniforms?: {[key: string]: Array} | undefined}; export type MotionCommandSetEffect = {backdrop?: boolean | undefined, effectId: string, enabled?: boolean | undefined, node: string, params?: ({[key: string]: number | string | boolean | Array | Array> | {x: number, y: number}}) | undefined, preset?: string | undefined, type: 'setEffect'}; export type MotionCommandRemoveEffect = {effectId: string, node: string, type: 'removeEffect'}; export type MotionCommandMoveEffect = {effectId: string, index: number, node: string, type: 'moveEffect'}; export type MotionCommandSetMasks = {masks: Array<{expansion?: number | undefined, feather?: number | undefined, featherFalloff?: ('smooth' | 'linear') | undefined, featherPoints?: (Array<{at: number, id?: string | undefined, radius: number}>) | undefined, height?: number | undefined, inverted?: boolean | undefined, mode?: ('add' | 'subtract' | 'intersect' | 'lighten' | 'darken' | 'difference' | 'none') | undefined, opacity?: number | undefined, path?: string | undefined, radius?: number | undefined, shape: 'rect' | 'ellipse' | 'path', width?: number | undefined, x?: number | undefined, y?: number | undefined}>, node: string, type: 'setMasks'}; export type MotionCommandSetMatte = {matte: string | null, mode?: ('alpha' | 'alphaInverted' | 'luma' | 'lumaInverted') | undefined, node: string, showMatte?: boolean | undefined, type: 'setMatte'}; export type MotionCommandGroup = {name?: string | undefined, nodeId?: string | undefined, nodes: Array, type: 'group'}; export type MotionCommandUngroup = {node: string, type: 'ungroup'}; export type MotionCommandStagger = {interval: number, nodes: Array, start?: number | undefined, type: 'stagger'}; export type MotionCommandApplyLook = {from: string, include?: (Array<'style' | 'effects'>) | undefined, nodes: Array, type: 'applyLook'}; export type MotionCommandFitCanvas = {padding?: number | undefined, type: 'fitCanvas'}; export type MotionCommandSetMarkers = {markers: Array<{at: number, duration?: number | undefined, id?: string | undefined, label?: string | undefined}>, node: string, type: 'setMarkers'}; export type MotionCommandSetTimeRemap = {keys: Array<{at: number, easing?: ('linear' | 'hold' | 'ease') | undefined, source: number}> | null, node: string, type: 'setTimeRemap'}; export type MotionCommandSetExpression = {expression: {amount: number, frequency: number, kind: 'wiggle', seed?: number | undefined} | {kind: 'noWiggle'} | {amount: number, band?: {from: number, to: number} | undefined, channel?: ('mono' | 'left' | 'right') | undefined, kind: 'audio', sound: string} | {kind: 'noAudio'} | {direction: 'in' | 'out', keyframes?: number | undefined, kind: 'loop', mode: 'cycle' | 'pingPong' | 'offset' | 'continue'} | {direction: 'in' | 'out', kind: 'noLoop'}, node: string, property: string, type: 'setExpression'}; export type MotionCommandSetTextAnimation = {duration?: number | undefined, from?: ('start' | 'end' | 'center' | 'edges' | 'random') | undefined, node: string, phase: 'in' | 'out', preset: 'typewriter' | 'fade' | 'rise' | 'drop' | 'pop' | 'blur' | 'slideLeft' | 'slideRight' | 'spread' | 'spin' | null, stagger?: number | undefined, type: 'setTextAnimation', unit?: ('character' | 'word' | 'line') | undefined}; export type MotionCommandAddPath = {cap?: ('butt' | 'round' | 'square') | undefined, color?: string | undefined, duration?: number | undefined, join?: ('miter' | 'round' | 'bevel') | undefined, nodeId?: string | undefined, paint?: ('fill' | 'stroke' | 'both') | undefined, parent?: string | undefined, path: string, start: number, strokeWidth?: number | undefined, type: 'addPath'}; export type MotionCommandSetPath = {cap?: ('butt' | 'round' | 'square') | undefined, color?: string | undefined, join?: ('miter' | 'round' | 'bevel') | undefined, keys?: (Array<{at: number, easing?: ('linear' | 'hold' | 'easyEase' | 'easyEaseIn' | 'easyEaseOut' | 'autoBezier' | 'easeInOutSine' | 'easeInOutCubic' | 'easeInOutExpo' | 'easeOutCubic' | 'easeInCubic' | 'easeOutBack' | 'easeInOutBack' | 'springGentle' | 'springBouncy' | {x1: number, x2: number, y1: number, y2: number} | {inInfluence?: number | undefined, outInfluence?: number | undefined, speed?: number | undefined}) | undefined, path: string}>) | undefined, node: string, paint?: ('fill' | 'stroke' | 'both') | undefined, path?: string | undefined, strokeWidth?: number | undefined, type: 'setPath'}; export type MotionCommandDuck = {amountDb?: number | undefined, attack?: number | undefined, node: string, release?: number | undefined, type: 'duck', under: Array}; export type MotionCommandExpect = {at?: number | undefined, exists?: boolean | undefined, node?: string | undefined, property?: string | undefined, tolerance?: number | undefined, type: 'expect', value?: (number | string) | undefined}; export type MotionCommandSetFades = {fadeIn?: number | undefined, fadeOut?: number | undefined, node: string, type: 'setFades'}; export type MotionOp = {type: 'document.rename' | 'canvas.set' | 'node.insert' | 'node.remove' | 'node.patch' | 'node.move' | 'node.trim' | 'node.wrap' | 'node.unwrap' | 'node.rewrap' | 'node.split' | 'meta.set' | 'asset.set' | 'asset.remove' | 'composition.set' | 'composition.remove' | 'transition.set' | 'transition.remove' | 'curve.set'} | {[key: string]: unknown}; export type MotionEdit = MotionCommandSetCurve | MotionCommandBindProperty | MotionCommandSplit | MotionCommandTrim | MotionCommandDelete | MotionCommandDuplicate | MotionCommandSetSpeed | MotionCommandSetTransition | MotionCommandAddTitle | MotionCommandAddShape | MotionCommandAddMedia | MotionCommandSetTitle | MotionCommandSetShape | MotionCommandAnimate | MotionCommandSetProperty | MotionCommandSetKeyframes | MotionCommandEditKeyframe | MotionCommandRemoveKeyframes | MotionCommandAddEffect | MotionCommandSetEffect | MotionCommandRemoveEffect | MotionCommandMoveEffect | MotionCommandSetMasks | MotionCommandSetMatte | MotionCommandGroup | MotionCommandUngroup | MotionCommandStagger | MotionCommandApplyLook | MotionCommandFitCanvas | MotionCommandSetMarkers | MotionCommandSetTimeRemap | MotionCommandSetExpression | MotionCommandSetTextAnimation | MotionCommandAddPath | MotionCommandSetPath | MotionCommandDuck | MotionCommandExpect | MotionCommandSetFades | MotionOp; export type DuplicateMotionDocumentRequest = {commands?: Array | undefined, name: string}; export type CreateApiV1MotionDocumentsIdDuplicateArgs = {id: string, body: DuplicateMotionDocumentRequest}; export type CreateApiV1MotionDocumentsIdDuplicateOptions = {baseUrl?: string | undefined, BearerAuth?: string | undefined, fetch?: typeof fetch | undefined}; export const motionApplyResult = z.object({changed: z.boolean().optional(), ok: z.boolean(), seq: z.number().int().gte(-9007199254740991).lte(9007199254740991).optional()}).and(z.record(z.string(), z.unknown())); export const motionDocument = z.object({createdAt: z.string(), id: z.string(), name: z.string(), ownerID: z.string(), sceneID: z.string().optional(), scope: z.string()}); export const duplicateMotionDocumentResponse = z.object({applied: motionApplyResult.optional(), document: motionDocument}); 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 }; /** * Duplicate a Tella Motion document * * POST /v1/motion/documents/{id}/duplicate */ export const createApiV1MotionDocumentsIdDuplicate = async (args: CreateApiV1MotionDocumentsIdDuplicateArgs, options?: CreateApiV1MotionDocumentsIdDuplicateOptions) => { const {baseUrl = "https://api.tella.com", fetch: fetchFn = fetch, BearerAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (BearerAuth !== undefined) headers.set('authorization', `Bearer ${BearerAuth}`) const url = `${baseUrl.replace(/\/+$/, '')}/v1/motion/documents/${encodeURIComponent(String(args.id))}/duplicate${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(duplicateMotionDocumentResponse, await res.json()) };