diff --git a/api.oas3.yaml b/api.oas3.yaml index 9b144ff..d4b1f2a 100644 --- a/api.oas3.yaml +++ b/api.oas3.yaml @@ -23,8 +23,6 @@ info: **[Ingest API](#shotstack-ingest)** - [https://api.shotstack.io/ingest/{version}](#)
Ingest (upload, store and transform) source footage, images, audio and fonts to be used by the Edit API. - **[Create API](#shotstack-create)** - [https://api.shotstack.io/create/{version}](#)
- Generate images, videos, voice overs and text using built in and third party generative AI providers. servers: - url: https://api.shotstack.io/edit/{version} @@ -54,15 +52,6 @@ servers: - v1 - stage default: v1 - - url: https://api.shotstack.io/create/{version} - variables: - version: - description: >- - Set the stage to **v1** for production usage. Set to **stage** to use the development sandbox. - enum: - - v1 - - stage - default: v1 tags: - name: Edit @@ -84,14 +73,6 @@ tags: API provides endpoints to fetch and upload files and check their status and URLs. All ingested files are available directly from an S3 bucket URL or via CDN (Serve API). - - name: Create - description: >- - The Create API generates assets and media files using Generative AI services like text-to-speech and - text-to-avatar. A native text-to-speech service is included as well as integrations with third party providers. - Third party services include [HeyGen](https://www.heygen.com/) text-to-avatar, [ElevenLabs](https://elevenlabs.io/) - text-to-speech and [D-ID](https://www.d-id.com/) text-to-avatar. Assets can be used with the Edit API or - downloaded and used independently. - paths: /render: $ref: "./paths/render.yaml" @@ -129,15 +110,6 @@ paths: /upload: $ref: "./paths/upload.yaml" - # Because of the way we have our servers set up and Create and Serve share the same endpoint name and how yaml/swagger - # can't have duplicate keys - we use a temporary path name here /path_alias_createassets and rename it at built time - # to assets using sed. Better ideas welcomed! - /path_alias_createassets: - $ref: "./paths/generateasset.yaml" - - # Using path alias and sed for replacement. See above comment. - /path_alias_createassets/{id}: - $ref: "./paths/generateassetid.yaml" components: schemas: @@ -441,73 +413,6 @@ components: Transfer: $ref: "./schemas/serve/transfer.yaml#/Transfer" - # Create schemas - GeneratedAsset: - $ref: "./schemas/create/generatedAsset.yaml#/GeneratedAsset" - - ShotstackGeneratedAsset: - $ref: "./schemas/create/shotstackGeneratedAsset.yaml#/ShotstackGeneratedAsset" - - ShotstackGeneratedAssetOptions: - $ref: "./schemas/create/shotstackGeneratedAssetOptions.yaml#/ShotstackGeneratedAssetOptions" - - ShotstackTextToSpeechOptions: - $ref: "./schemas/create/shotstackTextToSpeechOptions.yaml#/ShotstackTextToSpeechOptions" - - ShotstackTextToImageOptions: - $ref: "./schemas/create/shotstackTextToImageOptions.yaml#/ShotstackTextToImageOptions" - - ShotstackImageToVideoOptions: - $ref: "./schemas/create/shotstackImageToVideoOptions.yaml#/ShotstackImageToVideoOptions" - - ShotstackTextGeneratorOptions: - $ref: "./schemas/create/shotstackTextGeneratorOptions.yaml#/ShotstackTextGeneratorOptions" - - DIDGeneratedAsset: - $ref: "./schemas/create/didGeneratedAsset.yaml#/DIDGeneratedAsset" - - DIDGeneratedAssetOptions: - $ref: "./schemas/create/didGeneratedAssetOptions.yaml#/DIDGeneratedAssetOptions" - - DIDTextToAvatarOptions: - $ref: "./schemas/create/didTextToAvatarOptions.yaml#/DIDTextToAvatarOptions" - - ElevenLabsGeneratedAsset: - $ref: "./schemas/create/elevenlabsGeneratedAsset.yaml#/ElevenLabsGeneratedAsset" - - ElevenLabsGeneratedAssetOptions: - $ref: "./schemas/create/elevenlabsGeneratedAssetOptions.yaml#/ElevenLabsGeneratedAssetOptions" - - ElevenLabsTextToSpeechOptions: - $ref: "./schemas/create/elevenlabsTextToSpeechOptions.yaml#/ElevenLabsTextToSpeechOptions" - - HeyGenGeneratedAsset: - $ref: "./schemas/create/heygenGeneratedAsset.yaml#/HeyGenGeneratedAsset" - - HeyGenGeneratedAssetOptions: - $ref: "./schemas/create/heygenGeneratedAssetOptions.yaml#/HeyGenGeneratedAssetOptions" - - HeyGenTextToAvatarOptions: - $ref: "./schemas/create/heygenTextToAvatarOptions.yaml#/HeyGenTextToAvatarOptions" - - OpenAiGeneratedAsset: - $ref: "./schemas/create/openaiGeneratedAsset.yaml#/OpenAiGeneratedAsset" - - OpenAiGeneratedAssetOptions: - $ref: "./schemas/create/openaiGeneratedAssetOptions.yaml#/OpenAiGeneratedAssetOptions" - - OpenAiTextGeneratorOptions: - $ref: "./schemas/create/openaiTextGeneratorOptions.yaml#/OpenAiTextGeneratorOptions" - - StabilityAiGeneratedAsset: - $ref: "./schemas/create/stabilityAiGeneratedAsset.yaml#/StabilityAiGeneratedAsset" - - StabilityAiGeneratedAssetOptions: - $ref: "./schemas/create/stabilityAiGeneratedAssetOptions.yaml#/StabilityAiGeneratedAssetOptions" - - StabilityAiTextToImageOptions: - $ref: "./schemas/create/stabilityAiTextToImageOptions.yaml#/StabilityAiTextToImageOptions" - # Edit response schemas QueuedResponse: $ref: "./schemas/responses/queuedresponse.yaml#/QueuedResponse" @@ -607,22 +512,6 @@ components: IngestErrorResponseData: $ref: "./schemas/ingest/responses/ingesterrorresponsedata.yaml#/IngestErrorResponseData" - # Create response schemas - GeneratedAssetResponse: - $ref: "./schemas/create/responses/generatedAssetResponse.yaml#/GeneratedAssetResponse" - - GeneratedAssetResponseData: - $ref: "./schemas/create/responses/generatedAssetResponseData.yaml#/GeneratedAssetResponseData" - - GeneratedAssetResponseAttributes: - $ref: "./schemas/create/responses/generatedAssetResponseAttributes.yaml#/GeneratedAssetResponseAttributes" - - GeneratedAssetErrorResponse: - $ref: "./schemas/create/responses/generatedAssetErrorResponse.yaml#/GeneratedAssetErrorResponse" - - GeneratedAssetErrorResponseData: - $ref: "./schemas/create/responses/generatedAssetErrorResponseData.yaml#/GeneratedAssetErrorResponseData" - responses: {} parameters: {} examples: {} diff --git a/schemas/svgasset.yaml b/schemas/svgasset.yaml index 39f9aeb..cd74343 100644 --- a/schemas/svgasset.yaml +++ b/schemas/svgasset.yaml @@ -1,50 +1,29 @@ SvgAsset: description: | - The SvgAsset is used to add scalable vector graphics (SVG) shapes to a video. - It provides two mutually exclusive ways to define shapes: + The SvgAsset is used to add scalable vector graphics (SVG) to a video using raw SVG markup. - **Option 1: Import SVG markup using `src`** ```json { "type": "svg", "src": "" } ``` - When using `src`, no other properties are allowed. The fill, stroke, and dimensions - are automatically extracted from the SVG markup. - **Option 2: Define shapes programmatically using `shape`** - ```json - { - "type": "svg", - "shape": { "type": "circle", "radius": 50 }, - "fill": { "type": "solid", "color": "#FF0000" } - } - ``` - When using `shape`, you can customize fill, stroke, shadow, transform, and other properties. - The `src` property is not allowed in this mode. - - **Important:** You must provide either `src` OR `shape`, but not both. - These two modes are mutually exclusive. + **Supported elements:** ``, ``, ``, ``, + ``, ``, `` - **Available Shapes (Option 2 only):** - - `rectangle` - Rectangles with optional rounded corners - - `circle` - Perfect circles - - `ellipse` - Ellipses/ovals with separate x and y radii - - `line` - Straight lines with configurable thickness - - `polygon` - Regular polygons (triangle, pentagon, hexagon, etc.) - - `star` - Multi-pointed stars - - `arrow` - Directional arrows - - `heart` - Heart shapes - - `cross` - Plus/cross shapes - - `ring` - Donut/ring shapes - - `path` - Custom shapes using SVG path data + **Automatically extracted from SVG markup:** + - Path data (converted to a single combined path) + - Fill color (from `fill` attribute or `style`) + - Stroke color and width (from attributes or `style`) + - Dimensions (from `width`/`height` or `viewBox`) + - Opacity (from `opacity` attribute) See [W3C SVG 2 Specification](https://www.w3.org/TR/SVG2/) for path data syntax. type: object properties: type: - description: The asset type - set to `svg` for SVG shapes. + description: The asset type - set to `svg` for SVG assets. type: string enum: - svg @@ -52,123 +31,16 @@ SvgAsset: example: svg src: description: | - Raw SVG markup string to import. When provided, the shape is extracted - automatically from the SVG content. - - **Supported elements:** ``, ``, ``, ``, - ``, ``, `` - - **Automatically extracted:** - - Path data (converted to a single combined path) - - Fill color (from `fill` attribute or `style`) - - Stroke color and width (from attributes or `style`) - - Dimensions (from `width`/`height` or `viewBox`) - - Opacity (from `opacity` attribute) - - **Important:** When using `src`, no other properties (shape, fill, stroke, etc.) - are allowed. All styling must be defined within the SVG markup itself. + Raw SVG markup string. The shape, fill, stroke, dimensions and opacity + are automatically extracted from the SVG content. type: string minLength: 1 maxLength: 500000 example: '' - shape: - description: | - The shape definition using primitives. The `type` property within determines - the shape kind and its specific properties. - - **Important:** When using `shape`, the `src` property is not allowed. - $ref: "./svgshapes.yaml#/SvgShape" - fill: - description: | - Fill properties for the shape interior. - Can be a solid color or a gradient (linear/radial). - If omitted, the shape will have no fill (transparent interior). - - **Note:** Only allowed when using `shape`, not with `src`. - $ref: "./svgproperties.yaml#/SvgFill" - stroke: - description: | - Stroke (outline) properties for the shape. - If omitted, the shape will have no stroke (no outline). - - **Note:** Only allowed when using `shape`, not with `src`. - $ref: "./svgproperties.yaml#/SvgStroke" - shadow: - description: | - Drop shadow properties for the shape. - Creates a shadow effect behind the shape. - - **Note:** Only allowed when using `shape`, not with `src`. - $ref: "./svgproperties.yaml#/SvgShadow" - transform: - description: | - Transform properties for positioning, rotating, and scaling the shape. - The transform is applied relative to the transformation origin. - - **Note:** Only allowed when using `shape`, not with `src`. - $ref: "./svgproperties.yaml#/SvgTransform" - opacity: - description: | - The overall opacity of the entire shape (including fill, stroke, and shadow). - `1` is fully opaque, `0` is fully transparent. - This is applied on top of individual fill/stroke/shadow opacity values. - - **Note:** Only allowed when using `shape`, not with `src`. - type: number - minimum: 0 - maximum: 1 - default: 1 - example: 1 - width: - description: | - The width of the bounding box in pixels. - If specified, the shape may be scaled to fit within this width. - If omitted, the shape uses its natural dimensions. - - **Note:** Only allowed when using `shape`, not with `src`. - type: integer - minimum: 1 - maximum: 4096 - example: 400 - height: - description: | - The height of the bounding box in pixels. - If specified, the shape may be scaled to fit within this height. - If omitted, the shape uses its natural dimensions. - - **Note:** Only allowed when using `shape`, not with `src`. - type: integer - minimum: 1 - maximum: 4096 - example: 300 additionalProperties: false required: - type + - src example: type: svg - shape: - type: star - points: 5 - outerRadius: 100 - innerRadius: 50 - fill: - type: linear - angle: 45 - stops: - - offset: 0 - color: "#FFD700" - - offset: 1 - color: "#FF6B6B" - opacity: 1 - stroke: - color: "#2C3E50" - width: 3 - opacity: 1 - lineCap: round - lineJoin: round - transform: - x: 200 - y: 150 - rotation: 0 - scale: 1 - opacity: 1 + src: '' diff --git a/scripts/fix-discriminator.cjs b/scripts/fix-discriminator.cjs index 6609bb9..853e74e 100644 --- a/scripts/fix-discriminator.cjs +++ b/scripts/fix-discriminator.cjs @@ -125,48 +125,8 @@ const svgAssetPattern = // Note: Do NOT include z.preprocess here - the number coercion pass will add it const svgAssetSuperRefine = `export const svgassetSvgAssetSchema = z.object({ type: z.enum(["svg"]), - src: z.optional(z.string().min(1).max(500000)), - shape: z.optional(svgshapesSvgShapeSchema), - fill: z.optional(svgpropertiesSvgFillSchema), - stroke: z.optional(svgpropertiesSvgStrokeSchema), - shadow: z.optional(svgpropertiesSvgShadowSchema), - transform: z.optional(svgpropertiesSvgTransformSchema), - opacity: z.optional(z.number().gte(0).lte(1)).default(1), - width: z.optional(z.number().int().gte(1).lte(4096)), - height: z.optional(z.number().int().gte(1).lte(4096)), -}).superRefine((data, ctx) => { - const hasShape = data.shape !== undefined; - const hasSrc = data.src !== undefined && data.src.trim() !== ""; - - if (!hasShape && !hasSrc) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: "Either 'src' or 'shape' must be provided", - path: [], - }); - } - - if (hasShape && hasSrc) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: "Provide either 'src' or 'shape', not both", - path: ["src"], - }); - } - - if (hasSrc) { - const disallowedProps = ["shape", "fill", "stroke", "shadow", "transform", "width", "height"]; - for (const prop of disallowedProps) { - if (data[prop] !== undefined) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: \`'\${prop}' is not allowed when using 'src'. Only 'type' and 'src' are allowed in import mode\`, - path: [prop], - }); - } - } - } -});`; + src: z.string().min(1).max(500000), +}).strict();`; if (svgAssetPattern.test(content)) { content = content.replace(svgAssetPattern, svgAssetSuperRefine); @@ -492,48 +452,8 @@ if (fs.existsSync(zodGenCjsPath)) { // Note: Do NOT include z.preprocess here - the number coercion pass will add it const cjsSvgAssetSuperRefine = `exports.svgassetSvgAssetSchema = zod_1.z.object({ type: zod_1.z.enum(["svg"]), - src: zod_1.z.optional(zod_1.z.string().min(1).max(500000)), - shape: zod_1.z.optional(exports.svgshapesSvgShapeSchema), - fill: zod_1.z.optional(exports.svgpropertiesSvgFillSchema), - stroke: zod_1.z.optional(exports.svgpropertiesSvgStrokeSchema), - shadow: zod_1.z.optional(exports.svgpropertiesSvgShadowSchema), - transform: zod_1.z.optional(exports.svgpropertiesSvgTransformSchema), - opacity: zod_1.z.optional(zod_1.z.number().gte(0).lte(1)).default(1), - width: zod_1.z.optional(zod_1.z.number().int().gte(1).lte(4096)), - height: zod_1.z.optional(zod_1.z.number().int().gte(1).lte(4096)), -}).superRefine((data, ctx) => { - const hasShape = data.shape !== undefined; - const hasSrc = data.src !== undefined && data.src.trim() !== ""; - - if (!hasShape && !hasSrc) { - ctx.addIssue({ - code: zod_1.z.ZodIssueCode.custom, - message: "Either 'src' or 'shape' must be provided", - path: [], - }); - } - - if (hasShape && hasSrc) { - ctx.addIssue({ - code: zod_1.z.ZodIssueCode.custom, - message: "Provide either 'src' or 'shape', not both", - path: ["src"], - }); - } - - if (hasSrc) { - const disallowedProps = ["shape", "fill", "stroke", "shadow", "transform", "width", "height"]; - for (const prop of disallowedProps) { - if (data[prop] !== undefined) { - ctx.addIssue({ - code: zod_1.z.ZodIssueCode.custom, - message: "'" + prop + "' is not allowed when using 'src'. Only 'type' and 'src' are allowed in import mode", - path: [prop], - }); - } - } - } -});`; + src: zod_1.z.string().min(1).max(500000), +}).strict();`; if (cjsSvgAssetPattern.test(cjsContent)) { cjsContent = cjsContent.replace(cjsSvgAssetPattern, cjsSvgAssetSuperRefine);