transloadit 6.0.1 → 6.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/README.md +2 -2
  2. package/dist/Transloadit.d.ts.map +1 -1
  3. package/dist/Transloadit.js +5 -7
  4. package/dist/Transloadit.js.map +1 -1
  5. package/dist/alphalib/englishInteger.d.ts +3 -0
  6. package/dist/alphalib/englishInteger.d.ts.map +1 -0
  7. package/dist/alphalib/englishInteger.js +13 -0
  8. package/dist/alphalib/englishInteger.js.map +1 -0
  9. package/dist/alphalib/lib/zodInputSemantics.d.ts +3 -1
  10. package/dist/alphalib/lib/zodInputSemantics.d.ts.map +1 -1
  11. package/dist/alphalib/lib/zodInputSemantics.js +17 -0
  12. package/dist/alphalib/lib/zodInputSemantics.js.map +1 -1
  13. package/dist/alphalib/types/robots/_image-describe-output.d.ts +55 -0
  14. package/dist/alphalib/types/robots/_image-describe-output.d.ts.map +1 -0
  15. package/dist/alphalib/types/robots/_image-describe-output.js +16 -0
  16. package/dist/alphalib/types/robots/_image-describe-output.js.map +1 -0
  17. package/dist/alphalib/types/robots/_image-facedetect-output.d.ts +30 -0
  18. package/dist/alphalib/types/robots/_image-facedetect-output.d.ts.map +1 -0
  19. package/dist/alphalib/types/robots/_image-facedetect-output.js +15 -0
  20. package/dist/alphalib/types/robots/_image-facedetect-output.js.map +1 -0
  21. package/dist/alphalib/types/robots/_index.d.ts +582 -48
  22. package/dist/alphalib/types/robots/_index.d.ts.map +1 -1
  23. package/dist/alphalib/types/robots/_index.js +84 -80
  24. package/dist/alphalib/types/robots/_index.js.map +1 -1
  25. package/dist/alphalib/types/robots/_instructions-primitives.d.ts +82 -0
  26. package/dist/alphalib/types/robots/_instructions-primitives.d.ts.map +1 -1
  27. package/dist/alphalib/types/robots/_instructions-primitives.js +46 -2
  28. package/dist/alphalib/types/robots/_instructions-primitives.js.map +1 -1
  29. package/dist/alphalib/types/robots/_ocr-output.d.ts +75 -0
  30. package/dist/alphalib/types/robots/_ocr-output.d.ts.map +1 -0
  31. package/dist/alphalib/types/robots/_ocr-output.js +15 -0
  32. package/dist/alphalib/types/robots/_ocr-output.js.map +1 -0
  33. package/dist/alphalib/types/robots/ai-chat.d.ts +12 -12
  34. package/dist/alphalib/types/robots/audio-encode.d.ts.map +1 -1
  35. package/dist/alphalib/types/robots/audio-encode.js +8 -1
  36. package/dist/alphalib/types/robots/audio-encode.js.map +1 -1
  37. package/dist/alphalib/types/robots/audio-split.d.ts.map +1 -1
  38. package/dist/alphalib/types/robots/audio-split.js +2 -0
  39. package/dist/alphalib/types/robots/audio-split.js.map +1 -1
  40. package/dist/alphalib/types/robots/digitalocean-store.d.ts +4 -4
  41. package/dist/alphalib/types/robots/digitalocean-store.js +1 -1
  42. package/dist/alphalib/types/robots/digitalocean-store.js.map +1 -1
  43. package/dist/alphalib/types/robots/document-convert.d.ts +8 -6
  44. package/dist/alphalib/types/robots/document-convert.d.ts.map +1 -1
  45. package/dist/alphalib/types/robots/document-convert.js +5 -5
  46. package/dist/alphalib/types/robots/document-convert.js.map +1 -1
  47. package/dist/alphalib/types/robots/document-extract.d.ts +4 -4
  48. package/dist/alphalib/types/robots/document-ocr.d.ts +8 -8
  49. package/dist/alphalib/types/robots/google-store.d.ts +32 -8
  50. package/dist/alphalib/types/robots/google-store.d.ts.map +1 -1
  51. package/dist/alphalib/types/robots/google-store.js +10 -2
  52. package/dist/alphalib/types/robots/google-store.js.map +1 -1
  53. package/dist/alphalib/types/robots/image-bgremove.d.ts +16 -16
  54. package/dist/alphalib/types/robots/image-describe.d.ts +17 -17
  55. package/dist/alphalib/types/robots/image-describe.d.ts.map +1 -1
  56. package/dist/alphalib/types/robots/image-describe.js +2 -1
  57. package/dist/alphalib/types/robots/image-describe.js.map +1 -1
  58. package/dist/alphalib/types/robots/image-facedetect.d.ts +9 -35
  59. package/dist/alphalib/types/robots/image-facedetect.d.ts.map +1 -1
  60. package/dist/alphalib/types/robots/image-facedetect.js +1 -11
  61. package/dist/alphalib/types/robots/image-facedetect.js.map +1 -1
  62. package/dist/alphalib/types/robots/image-generate.d.ts +20 -20
  63. package/dist/alphalib/types/robots/image-generate.js +1 -1
  64. package/dist/alphalib/types/robots/image-generate.js.map +1 -1
  65. package/dist/alphalib/types/robots/image-ocr.d.ts +8 -8
  66. package/dist/alphalib/types/robots/image-upscale.d.ts +17 -12
  67. package/dist/alphalib/types/robots/image-upscale.d.ts.map +1 -1
  68. package/dist/alphalib/types/robots/image-upscale.js +14 -2
  69. package/dist/alphalib/types/robots/image-upscale.js.map +1 -1
  70. package/dist/alphalib/types/robots/mega-store.d.ts +4 -4
  71. package/dist/alphalib/types/robots/mega-store.js +1 -1
  72. package/dist/alphalib/types/robots/mega-store.js.map +1 -1
  73. package/dist/alphalib/types/robots/s3-store.d.ts +8 -8
  74. package/dist/alphalib/types/robots/s3-store.d.ts.map +1 -1
  75. package/dist/alphalib/types/robots/s3-store.js +14 -2
  76. package/dist/alphalib/types/robots/s3-store.js.map +1 -1
  77. package/dist/alphalib/types/robots/speech-transcribe.d.ts +12 -12
  78. package/dist/alphalib/types/robots/text-speak.d.ts +8 -8
  79. package/dist/alphalib/types/robots/text-translate.d.ts +8 -8
  80. package/dist/alphalib/types/robots/video-adaptive.d.ts +16 -19
  81. package/dist/alphalib/types/robots/video-adaptive.d.ts.map +1 -1
  82. package/dist/alphalib/types/robots/video-adaptive.js +37 -3
  83. package/dist/alphalib/types/robots/video-adaptive.js.map +1 -1
  84. package/dist/alphalib/types/robots/video-concat.d.ts.map +1 -1
  85. package/dist/alphalib/types/robots/video-concat.js +7 -3
  86. package/dist/alphalib/types/robots/video-concat.js.map +1 -1
  87. package/dist/alphalib/types/robots/video-encode.d.ts.map +1 -1
  88. package/dist/alphalib/types/robots/video-encode.js +6 -0
  89. package/dist/alphalib/types/robots/video-encode.js.map +1 -1
  90. package/dist/alphalib/types/robots/video-generate.d.ts +20 -20
  91. package/dist/alphalib/types/robots/video-generate.js +1 -1
  92. package/dist/alphalib/types/robots/video-generate.js.map +1 -1
  93. package/dist/alphalib/types/robots/video-merge.d.ts.map +1 -1
  94. package/dist/alphalib/types/robots/video-merge.js +15 -1
  95. package/dist/alphalib/types/robots/video-merge.js.map +1 -1
  96. package/dist/alphalib/types/robots/video-split.d.ts.map +1 -1
  97. package/dist/alphalib/types/robots/video-split.js +2 -0
  98. package/dist/alphalib/types/robots/video-split.js.map +1 -1
  99. package/dist/alphalib/types/robots/video-subtitle.d.ts +47 -4
  100. package/dist/alphalib/types/robots/video-subtitle.d.ts.map +1 -1
  101. package/dist/alphalib/types/robots/video-subtitle.js +59 -46
  102. package/dist/alphalib/types/robots/video-subtitle.js.map +1 -1
  103. package/dist/alphalib/types/robots/vimeo-import.d.ts.map +1 -1
  104. package/dist/alphalib/types/robots/vimeo-import.js +1 -1
  105. package/dist/alphalib/types/robots/vimeo-import.js.map +1 -1
  106. package/dist/alphalib/types/robots/youtube-store.d.ts +37 -20
  107. package/dist/alphalib/types/robots/youtube-store.d.ts.map +1 -1
  108. package/dist/alphalib/types/robots/youtube-store.js +17 -29
  109. package/dist/alphalib/types/robots/youtube-store.js.map +1 -1
  110. package/dist/alphalib/youtubeCategories.d.ts +20 -0
  111. package/dist/alphalib/youtubeCategories.d.ts.map +1 -0
  112. package/dist/alphalib/youtubeCategories.js +21 -0
  113. package/dist/alphalib/youtubeCategories.js.map +1 -0
  114. package/dist/apiTypes.d.ts +12 -1
  115. package/dist/apiTypes.d.ts.map +1 -1
  116. package/dist/robots.d.ts.map +1 -1
  117. package/dist/robots.js +6 -0
  118. package/dist/robots.js.map +1 -1
  119. package/package.json +1 -1
  120. package/src/Transloadit.ts +4 -6
  121. package/src/alphalib/englishInteger.ts +14 -0
  122. package/src/alphalib/lib/zodInputSemantics.ts +22 -1
  123. package/src/alphalib/types/robots/_image-describe-output.ts +20 -0
  124. package/src/alphalib/types/robots/_image-facedetect-output.ts +19 -0
  125. package/src/alphalib/types/robots/_index.ts +100 -82
  126. package/src/alphalib/types/robots/_instructions-primitives.ts +51 -2
  127. package/src/alphalib/types/robots/_ocr-output.ts +19 -0
  128. package/src/alphalib/types/robots/audio-encode.ts +8 -1
  129. package/src/alphalib/types/robots/audio-split.ts +2 -0
  130. package/src/alphalib/types/robots/digitalocean-store.ts +1 -1
  131. package/src/alphalib/types/robots/document-convert.ts +8 -5
  132. package/src/alphalib/types/robots/google-store.ts +15 -4
  133. package/src/alphalib/types/robots/image-describe.ts +8 -1
  134. package/src/alphalib/types/robots/image-facedetect.ts +4 -13
  135. package/src/alphalib/types/robots/image-generate.ts +1 -1
  136. package/src/alphalib/types/robots/image-upscale.ts +17 -2
  137. package/src/alphalib/types/robots/mega-store.ts +1 -1
  138. package/src/alphalib/types/robots/s3-store.ts +14 -2
  139. package/src/alphalib/types/robots/video-adaptive.ts +37 -3
  140. package/src/alphalib/types/robots/video-concat.ts +7 -3
  141. package/src/alphalib/types/robots/video-encode.ts +6 -0
  142. package/src/alphalib/types/robots/video-generate.ts +1 -1
  143. package/src/alphalib/types/robots/video-merge.ts +15 -1
  144. package/src/alphalib/types/robots/video-split.ts +2 -0
  145. package/src/alphalib/types/robots/video-subtitle.ts +61 -46
  146. package/src/alphalib/types/robots/vimeo-import.ts +3 -1
  147. package/src/alphalib/types/robots/youtube-store.ts +26 -41
  148. package/src/alphalib/youtubeCategories.ts +24 -0
  149. package/src/apiTypes.ts +12 -1
  150. package/src/robots.ts +7 -0
@@ -0,0 +1,19 @@
1
+ import { z } from 'zod'
2
+
3
+ /** An OCR polygon vertex in pixel coordinates. Provider omissions belong at the property site. */
4
+ export const ocrBoundingVertexSchema = z.object({ x: z.number(), y: z.number() })
5
+
6
+ /** Complete OCR text and pixel coordinates shared by image/document result projections. */
7
+ export const ocrTextWithPolygonSchema = z.object({
8
+ text: z.string(),
9
+ boundingPolygon: z.array(ocrBoundingVertexSchema),
10
+ })
11
+
12
+ /** Full-granularity OCR JSON projection requiring complete polygons. */
13
+ export const ocrFullOutputSchema = z.array(ocrTextWithPolygonSchema)
14
+
15
+ /** The list-granularity OCR result used by both AWS and GCP. */
16
+ export const ocrTextListSchema = z.array(z.string())
17
+
18
+ /** A list-granularity metadata projection with recognized text required. */
19
+ export const ocrTextListMetaSchema = z.object({ recognized_text: ocrTextListSchema })
@@ -45,7 +45,14 @@ export const robotAudioEncodeInstructionsSchema = robotBase
45
45
  .boolean()
46
46
  .optional()
47
47
  .describe('Whether the results of this Step should be present in the Assembly Status JSON'),
48
- robot: z.literal('/audio/encode'),
48
+ // The page renders the purpose sentence separately; add only the spatial-audio section here.
49
+ robot: z.literal('/audio/encode').describe(`
50
+ ## iPhone spatial audio
51
+
52
+ Videos recorded with iPhone spatial audio can contain a stereo AAC track alongside an Apple Positional Audio Codec (APAC) track. When unsupported audio is present, this <dfn>Robot</dfn> keeps one supported audio track by default. Spatial audio is not preserved or converted.
53
+
54
+ Files containing only unsupported audio still fail. Individual audio track selections and stream-copy requests keep the tracks you select; the output format must support copied tracks.
55
+ `),
49
56
  bitrate: bitrateSchema.optional().describe(robotParameterDocs.audio_bitrate.description),
50
57
  sample_rate: sampleRateSchema
51
58
  .optional()
@@ -65,6 +65,8 @@ export const robotAudioSplitInstructionsSchema = robotBase
65
65
  .describe('Whether the results of this Step should be present in the Assembly Status JSON'),
66
66
  robot: z.literal('/audio/split').describe(`
67
67
  Splits an audio file into multiple segments based on an array of from/to durations. Each segment produces a separate output file. This is useful for cutting an audio file into parts, for example to insert ads later via [🤖/audio/concat](/docs/robots/audio-concat/).
68
+
69
+ For iPhone videos with spatial audio, see [iPhone spatial audio in 🤖/audio/encode](/docs/robots/audio-encode/#iphone-spatial-audio).
68
70
  `),
69
71
  segments: z
70
72
  .array(segmentSchema)
@@ -42,7 +42,7 @@ export const robotDigitaloceanStoreInstructionsSchema = robotBase
42
42
  .describe(`
43
43
  The URL prefix used for the returned URL, such as \`"https://my.cdn.com/some/path"\`.
44
44
  `),
45
- acl: storageAcl,
45
+ acl: storageAcl.default('private'),
46
46
  headers: z
47
47
  .record(z.string())
48
48
  .default({ 'Content-Type': '${file.mime}' })
@@ -6,6 +6,7 @@ import type {
6
6
 
7
7
  import { z } from 'zod'
8
8
 
9
+ import { zodCaseInsensitiveEnum } from '../../lib/zodInputSemantics.ts'
9
10
  import {
10
11
  createProcessingExample,
11
12
  defineRobot,
@@ -14,6 +15,11 @@ import {
14
15
  robotUse,
15
16
  } from './_instructions-primitives.ts'
16
17
 
18
+ /** Accepts Playwright's paper-format case variants while publishing canonical spellings. */
19
+ export const documentConvertPdfFormatSchema = zodCaseInsensitiveEnum(
20
+ z.enum(['A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'Ledger', 'Legal', 'Letter', 'Tabloid']),
21
+ )
22
+
17
23
  export const meta: RobotMetaInput = {
18
24
  ...robotDocumentProcessingMeta,
19
25
  example_code: createProcessingExample('converted', '/document/convert', {
@@ -209,11 +215,8 @@ Print PDF background graphics.
209
215
 
210
216
  Currently this parameter is only supported when converting from \`html\`.
211
217
  `),
212
- pdf_format: z
213
- .enum(['A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'Ledger', 'Legal', 'Letter', 'Tabloid'])
214
- .default('Letter')
215
- .describe(`
216
- PDF paper format.
218
+ pdf_format: documentConvertPdfFormatSchema.default('Letter').describe(`
219
+ PDF paper format. Values are case-insensitive.
217
220
 
218
221
  Currently this parameter is only supported when converting from \`html\`.
219
222
  `),
@@ -1,5 +1,5 @@
1
1
  import type {
2
- RobotDefinition,
2
+ RobotDefinitionWithHiddenFields,
3
3
  RobotMetaInput,
4
4
  RobotSchemaVariantTypes,
5
5
  } from './_instructions-primitives.ts'
@@ -8,7 +8,7 @@ import { z } from 'zod'
8
8
 
9
9
  import {
10
10
  createStorageStoreExample,
11
- defineRobot,
11
+ defineRobotWithHiddenFields,
12
12
  getGoogleCredentialsDescription,
13
13
  googleBase,
14
14
  robotBase,
@@ -87,8 +87,19 @@ The SSL URL of the file in the result JSON. The following [Assembly variables](/
87
87
  })
88
88
  .strict()
89
89
 
90
- export const robotDefinition: RobotDefinition<typeof robotGoogleStoreInstructionsSchema.shape> =
91
- defineRobot(meta, robotGoogleStoreInstructionsSchema)
90
+ // Credential alternatives stay optional while Templates and Assembly overrides are merged.
91
+ // GoogleStoreRobot validates the resolved values after credential injection.
92
+ const hiddenFields = {
93
+ bucket: z.string().optional(),
94
+ credentials: robotGoogleStoreInstructionsSchema.shape.credentials.optional(),
95
+ key_file_contents: z.string().optional(),
96
+ project_id: z.string().optional(),
97
+ }
98
+
99
+ export const robotDefinition: RobotDefinitionWithHiddenFields<
100
+ typeof robotGoogleStoreInstructionsSchema.shape,
101
+ typeof hiddenFields
102
+ > = defineRobotWithHiddenFields(meta, robotGoogleStoreInstructionsSchema, hiddenFields)
92
103
 
93
104
  export const {
94
105
  withHiddenFields: robotGoogleStoreInstructionsWithHiddenFieldsSchema,
@@ -17,6 +17,13 @@ import {
17
17
  robotUse,
18
18
  } from './_instructions-primitives.ts'
19
19
 
20
+ export {
21
+ imageDescribeFullMetaSchema,
22
+ imageDescribeFullOutputSchema,
23
+ imageDescribeLabelSchema,
24
+ imageDescribeListMetaSchema,
25
+ } from './_image-describe-output.ts'
26
+
20
27
  export const meta: RobotMetaInput = {
21
28
  ...robotArtificialIntelligenceMeta,
22
29
  example_code: createProcessingExample('described', '/image/describe', {
@@ -50,7 +57,7 @@ You can use the labels that we return in your application to automatically class
50
57
  Whether to return a full response (\`"full"\`) including confidence percentages for each found label, or just a flat list of labels (\`"list"\`).
51
58
  `),
52
59
  format: z
53
- .enum(['json', 'meta', 'text'])
60
+ .enum(['json', 'meta'])
54
61
  .default('json')
55
62
  .describe(`
56
63
  In what format to return the descriptions.
@@ -25,19 +25,10 @@ export const imageFacedetectFaceSelectionModes = [
25
25
 
26
26
  export const imageFacedetectFaceSelectionModeSchema = z.enum(imageFacedetectFaceSelectionModes)
27
27
 
28
- export const imageFacedetectFaceCoordinatesSchema = z
29
- .object({
30
- confidence: z.number().optional(),
31
- height: z.number(),
32
- width: z.number(),
33
- x1: z.number(),
34
- x2: z.number().optional(),
35
- y1: z.number(),
36
- y2: z.number().optional(),
37
- })
38
- .passthrough()
39
-
40
- export type ImageFacedetectFaceCoordinates = z.infer<typeof imageFacedetectFaceCoordinatesSchema>
28
+ export {
29
+ type ImageFacedetectFaceCoordinates,
30
+ imageFacedetectFaceCoordinatesSchema,
31
+ } from './_image-facedetect-output.ts'
41
32
 
42
33
  export const meta: RobotMetaInput = {
43
34
  ...robotArtificialIntelligenceMeta,
@@ -97,7 +97,7 @@ Best practice:
97
97
  'Prompt describing the desired image. For inpainting, describe what should appear in the masked/transparent region and that the rest should stay unchanged.',
98
98
  ),
99
99
  format: z
100
- .enum(['jpeg', 'jpg', 'png', 'gif', 'webp', 'svg'])
100
+ .enum(['jpeg', 'jpg', 'png', 'webp', 'svg'])
101
101
  .optional()
102
102
  .describe(
103
103
  'Output format. Defaults depend on model: png for Google and OpenAI models, svg for recraft-v3, jpeg for others. Google models currently return PNG only.',
@@ -6,6 +6,7 @@ import type {
6
6
 
7
7
  import { z } from 'zod'
8
8
 
9
+ import { formatEnglishInteger } from '../../englishInteger.ts'
9
10
  import { imageUpscaleDefaultModelIdentifier, imageUpscaleModelIdentifiers } from './_ai-models.ts'
10
11
  import {
11
12
  autoProviderDescription,
@@ -29,7 +30,13 @@ export const meta: RobotMetaInput = {
29
30
  purpose_words: 'Upscale images',
30
31
  title: 'Upscale images',
31
32
  name: 'ImageUpscaleRobot',
33
+ // Preserve the runtime fallback; positive provider costs replace it during usage accounting.
32
34
  minimumChargeUsd: 0.06,
35
+ providerCostPricing: {
36
+ provider: 'replicate',
37
+ model: imageUpscaleDefaultModelIdentifier,
38
+ models: [...imageUpscaleModelIdentifiers],
39
+ },
33
40
  stage: 'beta',
34
41
  }
35
42
 
@@ -39,6 +46,12 @@ const upscaleModelSchema = z
39
46
  const upscaleScaleSchema = z.union([z.literal(2), z.literal(4)]).default(2)
40
47
  const upscaleFaceEnhanceSchema = z.boolean().default(false)
41
48
 
49
+ /**
50
+ * Maximum input area accepted by the pinned Real-ESRGAN Replicate predictor.
51
+ * @see https://github.com/replicate/cog-real-esrgan/blob/6cbd5e6ce8bd0fa90db54af899a8a9a85eb3db41/predict.py#L19
52
+ */
53
+ export const realEsrganMaxInputPixels = 1448 * 1448
54
+
42
55
  export const robotImageUpscaleInstructionsSchema = robotBase
43
56
  .merge(robotUse)
44
57
  .extend({
@@ -47,11 +60,13 @@ export const robotImageUpscaleInstructionsSchema = robotBase
47
60
  model: upscaleModelSchema
48
61
  .optional()
49
62
  .describe(
50
- `The AI model to use for image upscaling. Defaults to ${upscaleModelSchema.parse(undefined)}.`,
63
+ `The AI model to use for image upscaling. Defaults to ${upscaleModelSchema.parse(undefined)}. Real-ESRGAN inputs exceeding ${formatEnglishInteger(realEsrganMaxInputPixels)} pixels are resized proportionally before upscaling.`,
51
64
  ),
52
65
  scale: upscaleScaleSchema
53
66
  .optional()
54
- .describe(`Upscale factor. Defaults to ${upscaleScaleSchema.parse(undefined)}.`),
67
+ .describe(
68
+ `Upscale factor, applied after any input resizing. Defaults to ${upscaleScaleSchema.parse(undefined)}. GFPGAN results are resized after restoration to match this factor.`,
69
+ ),
55
70
  face_enhance: upscaleFaceEnhanceSchema
56
71
  .optional()
57
72
  .describe(
@@ -39,7 +39,7 @@ export const robotMegaStoreInstructionsSchema = robotBase
39
39
  The URL to the result file will be returned in the <dfn>Assembly Status JSON</dfn>.
40
40
  `),
41
41
  path: storeFilePath,
42
- acl: storageAcl,
42
+ acl: storageAcl.default('private'),
43
43
  headers: z
44
44
  .record(z.string())
45
45
  .default({ 'Content-Type': '${file.mime}' })
@@ -17,7 +17,19 @@ import {
17
17
  } from './_instructions-primitives.ts'
18
18
 
19
19
  const s3StoreAclSchema = z
20
- .enum(['bucket-default', 'private', 'public', 'public-read'])
20
+ // AWS object canned ACLs, plus the existing omission sentinel and legacy `public` value.
21
+ // `log-delivery-write` is bucket-only: https://docs.aws.amazon.com/AmazonS3/latest/userguide/acl-overview.html#canned-acl
22
+ .enum([
23
+ 'authenticated-read',
24
+ 'aws-exec-read',
25
+ 'bucket-default',
26
+ 'bucket-owner-full-control',
27
+ 'bucket-owner-read',
28
+ 'private',
29
+ 'public',
30
+ 'public-read',
31
+ 'public-read-write',
32
+ ])
21
33
  .default('public-read')
22
34
 
23
35
  export const meta: RobotMetaInput = {
@@ -95,7 +107,7 @@ Short-lived AWS credentials are a matching set of \`key\`, \`secret\` and \`sess
95
107
  The URL prefix used for the returned URL, such as \`"http://my.cdn.com/some/path/"\`.
96
108
  `),
97
109
  acl: s3StoreAclSchema.describe(`
98
- The ACL used for this file. The default remains \`"${s3StoreAclSchema.parse(undefined)}"\`, which can conflict with S3 Block Public Access and disabled ACLs. For modern private buckets, explicitly set \`"bucket-default"\` to omit the generated ACL header, and do not supply ACL/grant headers in \`headers\`. \`"private"\` still sends an ACL.
110
+ The ACL used for this file. Supports AWS’s [canned ACLs for objects](https://docs.aws.amazon.com/AmazonS3/latest/userguide/acl-overview.html#canned-acl). Other S3-compatible providers may support different ACLs. The default remains \`"${s3StoreAclSchema.parse(undefined)}"\`, which can conflict with S3 Block Public Access and disabled ACLs. For modern private buckets, explicitly set \`"bucket-default"\` to omit the generated ACL header, and do not supply ACL/grant headers in \`headers\`. \`"private"\` still sends an ACL.
99
111
  `),
100
112
  check_integrity: z
101
113
  .boolean()
@@ -71,6 +71,16 @@ This <dfn>Robot</dfn> accepts all types of video files and audio files. Do not f
71
71
 
72
72
  This <dfn>Robot</dfn> is normally used in combination with [🤖/video/encode](/docs/robots/video-encode/). We have implemented video and audio encoding presets specifically for MPEG-Dash and HTTP Live Streaming support. These presets are prefixed with \`"dash/"\` and \`"hls/"\`. [View a HTTP Live Streaming demo here](/demos/video-encoding/implement-http-live-streaming/).
73
73
 
74
+ ### CMAF aspect ratios
75
+
76
+ CMAF aligns near-equal rendition aspect ratios, within 1% of the largest rendition, without re-encoding or changing pixel dimensions. This lets presets such as \`"hls/480p"\` and \`"hls/720p"\` support bitrate switching together.
77
+
78
+ Renditions with substantially different ratios, such as 4:3 and 16:9, keep their geometry in separate video groups. The Assembly warns because DASH players cannot switch bitrate between these groups. HLS still lists every variant. Use matching rendition ratios when custom FFmpeg options change video geometry or layout.
79
+
80
+ ### Segment alignment
81
+
82
+ HLS and CMAF video segments split at existing keyframes, so their actual duration can exceed \`segment_duration\`. To align renditions to four-second segments, set \`"ffmpeg": { "force_key_frames": "expr:gte(t,n_forced*4)" }\` in each preceding [🤖/video/encode](/docs/robots/video-encode/) Step. Replace \`4\` with your chosen segment duration and use the same value for every rendition. Set keyframe intervals during encoding; packaging cannot add keyframes to copied streams.
83
+
74
84
  ### Required CORS settings for MPEG-Dash and HTTP Live Streaming
75
85
 
76
86
  Playing back MPEG-Dash Manifest or HLS playlist files requires a proper CORS setup on the server-side. The file-serving server should be configured to add the following header fields to responses:
@@ -106,6 +116,26 @@ To set up CORS for your S3 bucket:
106
116
  The <dfn>Robot</dfn> gives its result files (segments, initialization segments, MPD manifest files and M3U8 playlist files) the right metadata property \`relative_path\`, so that you can store them easily using one of our storage <dfn>Robots</dfn>.
107
117
 
108
118
  In the \`path\` parameter of the storage <dfn>Robot</dfn> of your choice, use the <dfn>Assembly Variable</dfn> \`\${file.meta.relative_path}\` to store files in the proper paths to make the playlist files work.
119
+ `),
120
+ ffmpeg: robotFFmpegVideo.shape.ffmpeg.describe(`
121
+ Custom FFmpeg options are supported for the \`"hls"\` and \`"cmaf"\` techniques. Non-empty custom options are rejected for \`"dash"\`, the default technique.
122
+
123
+ These options apply to the packaging command, which copies the input streams by default. Set encoding options, such as keyframe intervals, in the preceding [🤖/video/encode](/docs/robots/video-encode/) Step.
124
+ `),
125
+ ffmpeg_stack: robotFFmpegVideo.shape.ffmpeg_stack
126
+ .removeDefault()
127
+ .default('v7.0.0')
128
+ .describe(`
129
+ Selects the FFmpeg stack for packaging. Defaults to \`"v7.0.0"\`. This Robot always uses at least \`"v7.0.0"\`; older stack selections are upgraded automatically.
130
+ `),
131
+ preset: robotFFmpegVideo.shape.preset.describe(`
132
+ This parameter has no effect on this Robot. Set the encoding preset in the preceding [🤖/video/encode](/docs/robots/video-encode/) Step.
133
+ `),
134
+ width: robotFFmpegVideo.shape.width.describe(`
135
+ This parameter has no effect on this Robot. Set the rendition width in the preceding [🤖/video/encode](/docs/robots/video-encode/) Step.
136
+ `),
137
+ height: robotFFmpegVideo.shape.height.describe(`
138
+ This parameter has no effect on this Robot. Set the rendition height in the preceding [🤖/video/encode](/docs/robots/video-encode/) Step.
109
139
  `),
110
140
  technique: z
111
141
  .enum(['dash', 'hls', 'cmaf'])
@@ -129,9 +159,9 @@ Only used when \`technique\` is \`"cmaf"\`. Defines the filename for the generat
129
159
  segment_duration: z
130
160
  .number()
131
161
  .int()
132
- .default(10)
162
+ .optional()
133
163
  .describe(`
134
- The duration for each segment in seconds.
164
+ The duration for each segment in seconds. When omitted, defaults to 4 seconds for MPEG-Dash and CMAF, and 10 seconds for HLS.
135
165
  `),
136
166
  closed_captions: z
137
167
  .boolean()
@@ -147,7 +177,11 @@ When set to \`true\` and using the \`"hls"\` technique, audio-only input files a
147
177
 
148
178
  When enabled, video inputs only include their video stream in the output segments (any muxed audio is excluded). Provide audio separately as audio-only input files.
149
179
 
150
- This option is only supported for the \`"hls"\` technique and has no effect when using \`"dash"\`.
180
+ Each rendition’s \`LANGUAGE\` comes from the first audio stream’s \`language\` tag in its audio-only input file, or \`"und"\` when the tag is missing. Set the tag on [🤖/audio/encode](/docs/robots/audio-encode/) with \`"ffmpeg": {"metadata:s:a:0": "language=deu"}\`, for example.
181
+
182
+ The first audio-only input in \`use.steps\` order becomes \`DEFAULT=YES\`; the other renditions have \`DEFAULT=NO\`. All audio renditions have \`AUTOSELECT=YES\`. Their \`NAME\` uses the audio stream’s \`title\` tag when present, otherwise its language’s English name (for example, \`"eng"\` becomes “English” and \`"deu"\` becomes “German”). Untagged audio is named “Unknown”; unrecognized language codes are used as the name. Duplicate names receive a numeric suffix.
183
+
184
+ This option only enables alternate audio renditions with the \`"hls"\` technique and does not change packaging with \`"dash"\` or \`"cmaf"\`. CMAF puts all audio in one adaptation set labeled with the first audio language. Setting \`audio_group: true\` with CMAF, or providing CMAF inputs with more than one known audio language (including tracks muxed in a single video), adds an Assembly warning; packaging continues with the existing CMAF output. For multi-language audio, use \`technique: "hls"\` with \`audio_group: true\`.
151
185
  `),
152
186
  })
153
187
  .strict()
@@ -89,9 +89,11 @@ Please note this parameter is independent of adding video fades between sections
89
89
  .boolean()
90
90
  .default(false)
91
91
  .describe(`
92
- When set to \`true\`, the concatenated video will contain chapter markers at the positions where the input videos are joined. Each chapter will be titled with the basename of the corresponding input video file.
92
+ When set to \`true\`, the concatenated video will contain a chapter marker where each input video starts in the output. Each chapter will be titled with the basename of the corresponding input video file. When a \`transition\` is enabled, the incoming clip’s chapter starts at the beginning of its transition, accounting for the overlap between clips.
93
93
 
94
94
  This is useful for navigation in video players that support chapter-based seeking.
95
+
96
+ In MP4 output, chapter markers add a \`bin_data\` track containing the chapter information. This is normal and does not affect video or audio playback.
95
97
  `),
96
98
  sort_by: inputSortBySchema,
97
99
  transition: z
@@ -104,7 +106,7 @@ Specifies the transition effect to apply between concatenated video clips.
104
106
  - \`"crossfade"\`: Applies a crossfade transition where the end of one clip gradually blends into the beginning of the next clip. Both video and audio are crossfaded.
105
107
  - \`"fade_to_black"\`: Applies a fade-to-black transition where each clip fades out to black before the next clip fades in from black.
106
108
 
107
- When using \`"crossfade"\` or \`"fade_to_black"\`, the \`transition_duration\` parameter controls how long the transition lasts. Note that crossfade transitions will reduce the total output duration since clips overlap during the transition.
109
+ When using \`"crossfade"\` or \`"fade_to_black"\`, the \`transition_duration\` parameter controls how long the transition lasts. Both effects overlap adjacent clips and reduce the total output duration by the applied transition duration at each join. The applied duration is capped at half of the shorter clip in each pair.
108
110
  `),
109
111
  transition_duration: z
110
112
  .number()
@@ -114,7 +116,9 @@ The duration of the transition effect in seconds. Only applies when \`transition
114
116
 
115
117
  For example, a value of \`1.0\` creates a 1-second transition between clips. The value can be a float for sub-second precision (e.g., \`0.5\` for 500 milliseconds) and must be greater than \`0\` whenever transitions are enabled.
116
118
 
117
- For crossfade transitions, this is the overlap duration where both clips are visible. For fade_to_black transitions, this is the total time for the fade out and fade in (half for each). The applied transition is capped at half of the shorter clip in each transition pair.
119
+ For crossfade transitions, this is the overlap duration where both clips are visible. For \`"fade_to_black"\`, the video fades out over approximately the first 20% of the transition and fades in over the remaining 80% (about 0.2 seconds out and 0.8 seconds in for a 1-second transition). Audio is crossfaded throughout the transition for both effects.
120
+
121
+ The applied transition is capped at half of the shorter clip in each transition pair. Both effects shorten the output by this applied duration at each join.
118
122
  `),
119
123
  })
120
124
  .strict()
@@ -39,6 +39,12 @@ export const robotVideoEncodeInstructionsSchema = robotBase
39
39
  robot: z.literal('/video/encode').describe(`
40
40
  The /video/encode Robot is a versatile tool for video processing that handles transcoding, resizing, and watermarking. It supports various formats including modern standards like HEVC (H.265), and provides features such as presets for common devices, custom FFmpeg parameters for powerusers, watermark positioning, and more.
41
41
 
42
+ ## iPhone spatial audio
43
+
44
+ Videos recorded with iPhone spatial audio can contain a stereo AAC track alongside an Apple Positional Audio Codec (APAC) track. When unsupported audio is present, this <dfn>Robot</dfn> keeps one supported audio track by default. Spatial audio is not preserved or converted.
45
+
46
+ Files containing only unsupported audio still fail. Individual audio track selections and stream-copy requests keep the tracks you select; the output format must support copied tracks.
47
+
42
48
  ## Adding text overlays with FFmpeg
43
49
 
44
50
  You can add text overlays to videos using FFmpeg's \`drawtext\` filter through this <dfn>Robot</dfn>'s \`ffmpeg\` parameter. Here are two examples — one with the default font and one with a custom font family name:
@@ -49,7 +49,7 @@ export const robotVideoGenerateInstructionsSchema = robotBase
49
49
  `The AI model to use for video generation. Defaults to ${videoGenerateDefaultModelIdentifier}.`,
50
50
  ),
51
51
  prompt: z.string().describe('The prompt describing the desired video content.'),
52
- format: z.enum(['mp4', 'gif']).optional().describe('Format of the generated video.'),
52
+ format: z.enum(['mp4']).optional().describe('Format of the generated video.'),
53
53
  seed: z.number().optional().describe(robotParameterDocs.seed.description),
54
54
  aspect_ratio: z.string().optional().describe('Aspect ratio of the generated video.'),
55
55
  height: z.number().optional().describe('Height of the generated video.'),
@@ -24,6 +24,8 @@ export const meta: RobotMetaInput = {
24
24
  steps: {
25
25
  merged: {
26
26
  robot: '/video/merge',
27
+ preset: 'empty',
28
+ ffmpeg: { f: 'mp4' },
27
29
  use: [
28
30
  { name: ':original', as: 'image' },
29
31
  { name: ':original', as: 'audio' },
@@ -51,7 +53,12 @@ export const robotVideoMergeInstructionsSchema = robotBase
51
53
  .merge(robotUse)
52
54
  .merge(robotFFmpegVideo)
53
55
  .extend({
54
- robot: z.literal('/video/merge'),
56
+ // The robot literal's description supplies the Robot page introduction.
57
+ robot: z.literal('/video/merge').describe(`
58
+ When concatenating videos end-to-end, all inputs must have the same width and height, with or without a \`transition\`. For joining clips, use [🤖/video/concat](/docs/robots/video-concat/), which pre-transcodes inputs to matching specifications when needed.
59
+
60
+ When both \`preset\` and \`ffmpeg\` are omitted, this Robot uses the legacy \`"flash"\` preset and outputs FLV. Choose an output preset or set \`ffmpeg.f\` explicitly to select another format, such as \`"mp4"\`.
61
+ `),
55
62
  resize_strategy: resize_strategy.describe(`
56
63
  If the given width/height parameters are bigger than the input image's dimensions, then the \`resize_strategy\` determines how the image will be resized to match the provided width/height. See the [available resize strategies](/docs/topics/resize-strategies/).
57
64
  `),
@@ -107,6 +114,7 @@ Stacks the input media vertically. All streams need to have the same pixel forma
107
114
  The URL of an image to be merged with the audio or video. When this parameter is provided, the robot will download the image from the URL and merge it with the other media.
108
115
  `),
109
116
  sort_by: inputSortBySchema,
117
+ // Include join constraints in parameter help as well as the Robot introduction.
110
118
  transition: z
111
119
  .enum(['none', 'crossfade', 'fade_to_black'])
112
120
  .default('none')
@@ -116,12 +124,18 @@ The type of transition effect to apply between concatenated video clips. Only ap
116
124
  - \`"none"\` — No transition effect. Videos are joined end-to-end.
117
125
  - \`"crossfade"\` — A gradual blend from one clip to the next (both video and audio).
118
126
  - \`"fade_to_black"\` — The current clip fades out to black, then the next clip fades in from black.
127
+
128
+ Both \`"crossfade"\` and \`"fade_to_black"\` overlap adjacent clips and shorten the output by the applied \`transition_duration\` at each join. The applied duration is capped at half of the shorter clip in each pair.
129
+
130
+ All concatenated videos must have the same width and height, even when \`transition\` is \`"none"\`. For joining clips with different dimensions, use [🤖/video/concat](/docs/robots/video-concat/).
119
131
  `),
120
132
  transition_duration: z
121
133
  .number()
122
134
  .default(1)
123
135
  .describe(`
124
136
  The duration of the transition effect in seconds. Only applies when \`transition\` is not \`"none"\`. Supports float values (e.g., \`0.5\` for a 500ms transition) and must be greater than \`0\` whenever transitions are enabled. The applied transition is automatically capped at half of the shorter clip in each transition pair to prevent overlapping transitions.
137
+
138
+ For \`"crossfade"\`, this is the overlap duration where both clips are visible. For \`"fade_to_black"\`, the video fades out over approximately the first 20% of the transition and fades in over the remaining 80% (about 0.2 seconds out and 0.8 seconds in for a 1-second transition). Audio is crossfaded throughout the transition for both effects. Both effects shorten the output by the applied duration at each join.
125
139
  `),
126
140
  })
127
141
  .strict()
@@ -57,6 +57,8 @@ export const robotVideoSplitInstructionsSchema = robotBase
57
57
  .extend({
58
58
  robot: z.literal('/video/split').describe(`
59
59
  Splits a video into multiple segments based on an array of from/to durations. Each segment produces a separate output file. This is useful for cutting a video into parts, for example to insert ads later via [🤖/video/concat](/docs/robots/video-concat/).
60
+
61
+ For iPhone videos with spatial audio, see [iPhone spatial audio in 🤖/video/encode](/docs/robots/video-encode/#iphone-spatial-audio).
60
62
  `),
61
63
  segments: z
62
64
  .array(segmentSchema)