transloadit 6.1.2 → 6.2.1

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 (75) hide show
  1. package/README.md +14 -0
  2. package/dist/alphalib/stepParsing.d.ts +1 -0
  3. package/dist/alphalib/stepParsing.d.ts.map +1 -1
  4. package/dist/alphalib/stepParsing.js +15 -4
  5. package/dist/alphalib/stepParsing.js.map +1 -1
  6. package/dist/alphalib/types/builtinTemplates.d.ts +40 -0
  7. package/dist/alphalib/types/builtinTemplates.d.ts.map +1 -1
  8. package/dist/alphalib/types/builtinTemplates.js +29 -0
  9. package/dist/alphalib/types/builtinTemplates.js.map +1 -1
  10. package/dist/alphalib/types/responseErrors/DocumentConvertRobot.d.ts +17 -0
  11. package/dist/alphalib/types/responseErrors/DocumentConvertRobot.d.ts.map +1 -0
  12. package/dist/alphalib/types/responseErrors/DocumentConvertRobot.js +17 -0
  13. package/dist/alphalib/types/responseErrors/DocumentConvertRobot.js.map +1 -0
  14. package/dist/alphalib/types/robots/document-convert.d.ts.map +1 -1
  15. package/dist/alphalib/types/robots/document-convert.js +19 -0
  16. package/dist/alphalib/types/robots/document-convert.js.map +1 -1
  17. package/dist/alphalib/types/robots/document-extract.d.ts +32 -20
  18. package/dist/alphalib/types/robots/document-extract.d.ts.map +1 -1
  19. package/dist/alphalib/types/robots/document-extract.js +51 -1
  20. package/dist/alphalib/types/robots/document-extract.js.map +1 -1
  21. package/dist/alphalib/types/robots/html-convert.d.ts.map +1 -1
  22. package/dist/alphalib/types/robots/html-convert.js +1 -0
  23. package/dist/alphalib/types/robots/html-convert.js.map +1 -1
  24. package/dist/alphalib/types/robots/speech-transcribe.d.ts +14 -0
  25. package/dist/alphalib/types/robots/speech-transcribe.d.ts.map +1 -1
  26. package/dist/alphalib/types/robots/speech-transcribe.js +42 -2
  27. package/dist/alphalib/types/robots/speech-transcribe.js.map +1 -1
  28. package/dist/alphalib/types/robots/video-split.d.ts +11 -0
  29. package/dist/alphalib/types/robots/video-split.d.ts.map +1 -1
  30. package/dist/alphalib/types/robots/video-split.js +2 -1
  31. package/dist/alphalib/types/robots/video-split.js.map +1 -1
  32. package/dist/alphalib/types/robots/video-subtitle.d.ts +24 -24
  33. package/dist/alphalib/types/robots/video-subtitle.d.ts.map +1 -1
  34. package/dist/alphalib/types/robots/video-subtitle.js +12 -11
  35. package/dist/alphalib/types/robots/video-subtitle.js.map +1 -1
  36. package/dist/alphalib/types/robots/video-thumbs.d.ts +36 -36
  37. package/dist/alphalib/types/robots/video-thumbs.d.ts.map +1 -1
  38. package/dist/alphalib/types/robots/video-thumbs.js +8 -3
  39. package/dist/alphalib/types/robots/video-thumbs.js.map +1 -1
  40. package/dist/alphalib/types/template.d.ts.map +1 -1
  41. package/dist/alphalib/types/template.js +5 -2
  42. package/dist/alphalib/types/template.js.map +1 -1
  43. package/dist/cli/commands/assemblies.js +3 -3
  44. package/dist/cli/commands/assemblies.js.map +1 -1
  45. package/dist/cli/commands/auth.d.ts.map +1 -1
  46. package/dist/cli/commands/auth.js +4 -3
  47. package/dist/cli/commands/auth.js.map +1 -1
  48. package/dist/cli/commands/templates.d.ts.map +1 -1
  49. package/dist/cli/commands/templates.js +11 -5
  50. package/dist/cli/commands/templates.js.map +1 -1
  51. package/dist/cli/stepsInput.d.ts +6 -2
  52. package/dist/cli/stepsInput.d.ts.map +1 -1
  53. package/dist/cli/stepsInput.js +24 -5
  54. package/dist/cli/stepsInput.js.map +1 -1
  55. package/dist/cli/types.d.ts +0 -1
  56. package/dist/cli/types.d.ts.map +1 -1
  57. package/dist/cli/types.js +0 -7
  58. package/dist/cli/types.js.map +1 -1
  59. package/package.json +1 -1
  60. package/src/alphalib/stepParsing.ts +16 -4
  61. package/src/alphalib/types/builtinTemplates.ts +37 -0
  62. package/src/alphalib/types/responseErrors/DocumentConvertRobot.ts +21 -0
  63. package/src/alphalib/types/robots/document-convert.ts +25 -0
  64. package/src/alphalib/types/robots/document-extract.ts +76 -0
  65. package/src/alphalib/types/robots/html-convert.ts +1 -0
  66. package/src/alphalib/types/robots/speech-transcribe.ts +47 -2
  67. package/src/alphalib/types/robots/video-split.ts +2 -1
  68. package/src/alphalib/types/robots/video-subtitle.ts +12 -11
  69. package/src/alphalib/types/robots/video-thumbs.ts +8 -3
  70. package/src/alphalib/types/template.ts +3 -0
  71. package/src/cli/commands/assemblies.ts +3 -3
  72. package/src/cli/commands/auth.ts +7 -2
  73. package/src/cli/commands/templates.ts +13 -6
  74. package/src/cli/stepsInput.ts +34 -5
  75. package/src/cli/types.ts +0 -9
@@ -1 +1 @@
1
- {"version":3,"file":"stepsInput.d.ts","sourceRoot":"","sources":["../../src/cli/stepsInput.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAA;AAU/D,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAgC/D;AAED,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAG9E"}
1
+ {"version":3,"file":"stepsInput.d.ts","sourceRoot":"","sources":["../../src/cli/stepsInput.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAIhD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAQvB,mGAAmG;AACnG,wBAAgB,oBAAoB,CAClC,MAAM,GAAE,IAAI,CAAC,UAAU,EAAE,MAAM,CAAW,GACzC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAevB;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,IAAI,CAAC,UAAU,EAAE,MAAM,CAAW,GACzC,UAAU,CAgCZ;AAED,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,IAAI,CAAC,UAAU,EAAE,MAAM,CAAW,GACzC,OAAO,CAAC,UAAU,CAAC,CAGrB"}
@@ -1,8 +1,27 @@
1
1
  import fsp from 'node:fs/promises';
2
2
  import { z } from 'zod';
3
- import { stepsSchema } from "../alphalib/types/template.js";
3
+ import { robotsSchema } from "../alphalib/types/robots/_index.js";
4
+ import { refineDocumentExtractOcr } from "../alphalib/types/robots/document-extract.js";
5
+ import { refineTransloaditImportSelector } from "../alphalib/types/robots/transloadit-import.js";
4
6
  const stepsWrapperSchema = z.object({ steps: z.record(z.unknown()) });
5
- export function parseStepsInputJson(content) {
7
+ /** CLI inputs can be partial overrides; API2 validates OCR after merging their runtime context. */
8
+ export function createCliStepsSchema(output = console) {
9
+ const cliStepSchema = robotsSchema
10
+ .superRefine(refineTransloaditImportSelector)
11
+ .superRefine((step, context) => {
12
+ // API2 merges Template defaults before Robot validation. New OCR checks must not reject
13
+ // partial --steps overrides in a minor release; explicit Zod schemas remain strict.
14
+ refineDocumentExtractOcr(step, {
15
+ ...context,
16
+ addIssue(issue) {
17
+ const field = [...context.path, ...(issue.path ?? [])].join('.');
18
+ output.warn(`${field}: ${issue.message ?? 'Invalid OCR dependency.'}`);
19
+ },
20
+ });
21
+ });
22
+ return z.record(cliStepSchema);
23
+ }
24
+ export function parseStepsInputJson(content, output = console) {
6
25
  const parsed = JSON.parse(content);
7
26
  const wrapped = stepsWrapperSchema.safeParse(parsed);
8
27
  let stepsInput = parsed;
@@ -15,7 +34,7 @@ export function parseStepsInputJson(content) {
15
34
  }
16
35
  stepsInput = validatedWrapper.data.steps;
17
36
  }
18
- const validated = stepsSchema.safeParse(stepsInput);
37
+ const validated = createCliStepsSchema(output).safeParse(stepsInput);
19
38
  if (!validated.success) {
20
39
  throw new Error(`Invalid steps format: ${validated.error.message}`);
21
40
  }
@@ -29,8 +48,8 @@ export function parseStepsInputJson(content) {
29
48
  ];
30
49
  }));
31
50
  }
32
- export async function readStepsInputFile(filePath) {
51
+ export async function readStepsInputFile(filePath, output = console) {
33
52
  const content = await fsp.readFile(filePath, 'utf8');
34
- return parseStepsInputJson(content);
53
+ return parseStepsInputJson(content, output);
35
54
  }
36
55
  //# sourceMappingURL=stepsInput.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stepsInput.js","sourceRoot":"","sources":["../../src/cli/stepsInput.ts"],"names":[],"mappings":"AAEA,OAAO,GAAG,MAAM,kBAAkB,CAAA;AAElC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAE3D,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAA;AAErE,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAC3C,MAAM,OAAO,GAAG,kBAAkB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;IACpD,IAAI,UAAU,GAAG,MAAM,CAAA;IACvB,+EAA+E;IAC/E,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACpE,kFAAkF;QAClF,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;QACtE,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,yBAAyB,gBAAgB,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;QAC5E,CAAC;QACD,UAAU,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAA;IAC1C,CAAC;IACD,MAAM,SAAS,GAAG,WAAW,CAAC,SAAS,CAAC,UAAU,CAAC,CAAA;IACnD,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,yBAAyB,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;IACrE,CAAC;IAED,MAAM,WAAW,GAAG,UAAqD,CAAA;IACzE,MAAM,cAAc,GAAG,SAAS,CAAC,IAA+C,CAAA;IAEhF,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,EAAE;QACxD,MAAM,cAAc,GAAG,cAAc,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAA;QACrD,OAAO;YACL,QAAQ;YACR,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,cAAc,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAClF;SACF,CAAA;IACH,CAAC,CAAC,CACW,CAAA;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,QAAgB;IACvD,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;IACpD,OAAO,mBAAmB,CAAC,OAAO,CAAC,CAAA;AACrC,CAAC"}
1
+ {"version":3,"file":"stepsInput.js","sourceRoot":"","sources":["../../src/cli/stepsInput.ts"],"names":[],"mappings":"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"}
@@ -65,7 +65,6 @@ export interface TemplateFileData {
65
65
  steps?: Steps;
66
66
  [key: string]: unknown;
67
67
  }
68
- export declare const TemplateFileDataSchema: z.ZodType<TemplateFileData>;
69
68
  export interface TemplateFile {
70
69
  file: string;
71
70
  data: TemplateFileData;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAA;AAE1D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAKvB,QAAA,MAAM,cAAc;;;;;;;;;EAGlB,CAAA;AACF,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;AAErD,QAAA,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAe7B,CAAA;AACF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAG3E,MAAM,WAAW,gBAAgB;IAC/B,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,eAAO,MAAM,sBAAsB,EAAE,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAKhB,CAAA;AAE/C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,gBAAgB,CAAA;CACvB;AAGD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAKjD;AAGD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAE5D;AAGD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,mBAAmB,CAElF;AAGD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,cAAc,CAE/E"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAA;AAE1D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,QAAA,MAAM,cAAc;;;;;;;;;EAGlB,CAAA;AACF,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;AAErD,QAAA,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAe7B,CAAA;AACF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAG3E,MAAM,WAAW,gBAAgB;IAC/B,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,gBAAgB,CAAA;CACvB;AAGD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAKjD;AAGD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAE5D;AAGD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,mBAAmB,CAElF;AAGD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,cAAc,CAE/E"}
package/dist/cli/types.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { z } from 'zod';
2
- import { optionalStepsSchema } from "../alphalib/types/template.js";
3
2
  // Zod schemas for runtime validation
4
3
  const APIErrorSchema = z.object({
5
4
  error: z.string(),
@@ -21,12 +20,6 @@ const TransloaditAPIErrorSchema = z.object({
21
20
  })
22
21
  .optional(),
23
22
  });
24
- export const TemplateFileDataSchema = z
25
- .object({
26
- transloadit_template_id: z.string().optional(),
27
- steps: optionalStepsSchema,
28
- })
29
- .passthrough();
30
23
  // Helper to ensure error is Error type
31
24
  export function ensureError(value) {
32
25
  if (value instanceof Error) {
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAA;AAEnE,qCAAqC;AACrC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;CACpB,CAAC,CAAA;AAGF,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3C,QAAQ,EAAE,CAAC;SACR,MAAM,CAAC;QACN,IAAI,EAAE,CAAC;aACJ,MAAM,CAAC;YACN,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC7B,CAAC;aACD,QAAQ,EAAE;QACb,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAClC,CAAC;SACD,QAAQ,EAAE;CACd,CAAC,CAAA;AAUF,MAAM,CAAC,MAAM,sBAAsB,GAAgC,CAAC;KACjE,MAAM,CAAC;IACN,uBAAuB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9C,KAAK,EAAE,mBAAmB;CAC3B,CAAC;KACD,WAAW,EAAiC,CAAA;AAO/C,uCAAuC;AACvC,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAA;IACd,CAAC;IACD,OAAO,IAAI,KAAK,CAAC,yBAAyB,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;AAC5D,CAAC;AAED,0BAA0B;AAC1B,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,OAAO,cAAc,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAA;AAChD,CAAC;AAED,qCAAqC;AACrC,MAAM,UAAU,qBAAqB,CAAC,KAAc;IAClD,OAAO,yBAAyB,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAA;AAC3D,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,CAAA;AAClD,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,qCAAqC;AACrC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;CACpB,CAAC,CAAA;AAGF,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3C,QAAQ,EAAE,CAAC;SACR,MAAM,CAAC;QACN,IAAI,EAAE,CAAC;aACJ,MAAM,CAAC;YACN,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC7B,CAAC;aACD,QAAQ,EAAE;QACb,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAClC,CAAC;SACD,QAAQ,EAAE;CACd,CAAC,CAAA;AAeF,uCAAuC;AACvC,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAA;IACd,CAAC;IACD,OAAO,IAAI,KAAK,CAAC,yBAAyB,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;AAC5D,CAAC;AAED,0BAA0B;AAC1B,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,OAAO,cAAc,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAA;AAChD,CAAC;AAED,qCAAqC;AACrC,MAAM,UAAU,qBAAqB,CAAC,KAAc;IAClD,OAAO,yBAAyB,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAA;AAC3D,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,CAAA;AAClD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "transloadit",
3
- "version": "6.1.2",
3
+ "version": "6.2.1",
4
4
  "description": "Node.js SDK for Transloadit",
5
5
  "homepage": "https://github.com/transloadit/node-sdk/tree/main/packages/node",
6
6
  "bugs": {
@@ -1283,10 +1283,22 @@ function getMostCommonExampleValue(
1283
1283
  return mostCommonValue
1284
1284
  }
1285
1285
 
1286
- // Modify the extractFieldNamesFromTemplate function
1286
+ /** Finds field references even when Assembly overrides complete a stored Template. */
1287
1287
  export function extractFieldNamesFromTemplate(templateContent: string): ParsedTemplateField[] {
1288
- const [templateError, template] = parseSafeTemplate(templateContent)
1289
- if (templateError) {
1288
+ let template: unknown
1289
+ try {
1290
+ template = JSON.parse(templateContent)
1291
+ } catch {
1292
+ return []
1293
+ }
1294
+ // Discovery needs only the Steps' structure. Complete-instruction validation would
1295
+ // hide fields when, for example, an override supplies a required OCR provider.
1296
+ if (
1297
+ !isRecord(template) ||
1298
+ Array.isArray(template) ||
1299
+ !isRecord(template.steps) ||
1300
+ Array.isArray(template.steps)
1301
+ ) {
1290
1302
  return []
1291
1303
  }
1292
1304
  const fieldsMap = new Map<string, ParsedTemplateField>()
@@ -1335,7 +1347,7 @@ export function extractFieldNamesFromTemplate(templateContent: string): ParsedTe
1335
1347
  }
1336
1348
  }
1337
1349
 
1338
- for (const [stepName, step] of entries(template.steps || {})) {
1350
+ for (const [stepName, step] of entries(template.steps)) {
1339
1351
  if (typeof step !== 'object' || step === null) {
1340
1352
  continue
1341
1353
  }
@@ -22,3 +22,40 @@ export const builtinTemplateDocSchema = z
22
22
  export const builtinTemplateDocsSchema = z.array(builtinTemplateDocSchema)
23
23
 
24
24
  export type BuiltinTemplateDoc = z.infer<typeof builtinTemplateDocSchema>
25
+
26
+ /** Standalone catalog JSON Schema, or null when a Builtin has no declared fields contract. */
27
+ export const builtinTemplateFieldsSchema = z.record(z.string(), z.unknown()).nullable()
28
+
29
+ /**
30
+ * Runtime catalog projection used by Builtin clients. API2 supplies descriptions, field schemas
31
+ * and defaults; absent and null schemas remain distinct, and neither declares a usable contract.
32
+ */
33
+ export const builtinTemplateCatalogItemSchema = z.object({
34
+ id: z.string(),
35
+ description: z.string().optional(),
36
+ fields_schema: builtinTemplateFieldsSchema.optional(),
37
+ content: z.object({ fields: z.record(z.string(), z.unknown()).default({}) }),
38
+ })
39
+
40
+ /** Runtime catalog item after missing fields have been normalized to an empty object. */
41
+ export type BuiltinTemplateCatalogItem = z.infer<typeof builtinTemplateCatalogItemSchema>
42
+
43
+ /**
44
+ * MCP channel approvals: exact reviewed versions and temporarily excluded field values.
45
+ * Membership is explicit; a catalog schema, a new Builtin version, or Storage eligibility does
46
+ * not grant MCP approval. Keep runtime descriptions, schemas and defaults in API2's catalog.
47
+ */
48
+ export const mcpBuiltinTemplateManifest: Readonly<
49
+ Record<string, Readonly<Record<string, readonly string[]>>>
50
+ > = {
51
+ 'builtin/caption-video@0.0.1': {},
52
+ 'builtin/capture-webpage@0.0.1': {},
53
+ 'builtin/convert-to-pdf@0.0.1': {},
54
+ // Remove only after api2#9960 is deployed and its VP8/turbo output is verified.
55
+ 'builtin/encode-video@0.0.1': { preset: ['webm'] },
56
+ 'builtin/extract-text@0.0.1': {},
57
+ 'builtin/prepare-image@0.0.1': {},
58
+ 'builtin/remove-background@0.0.1': {},
59
+ 'builtin/transcribe@0.0.1': {},
60
+ 'builtin/video-covers@0.0.1': {},
61
+ }
@@ -0,0 +1,21 @@
1
+ /** Public reason when diagnostics identify a service-side document-loading failure. */
2
+ export const documentConvertLoadInternalErrorReason =
3
+ 'LibreOffice could not load the document. Please contact support.'
4
+
5
+ /** Public reason for a load refusal without evidence of a service-side failure. */
6
+ export const documentConvertLoadUserErrorReason =
7
+ 'LibreOffice could not load the document. It may be damaged, password-protected, or in an unsupported format. If it opens elsewhere, please contact support.'
8
+
9
+ /** DocumentConvertRobot error payloads shared by runtime and the Assembly Status contract. */
10
+ export const documentConvertRobotErrors = {
11
+ DOCUMENT_CONVERT_VALIDATION: {
12
+ error: 'DOCUMENT_CONVERT_VALIDATION',
13
+ http_code: 400,
14
+ },
15
+ DOCUMENT_CONVERT_UNSUPPORTED_CONVERSION: {
16
+ error: 'DOCUMENT_CONVERT_UNSUPPORTED_CONVERSION',
17
+ http_code: 400,
18
+ message:
19
+ "The conversion from the input file's format to the desired output format is not supported.",
20
+ },
21
+ } as const
@@ -7,6 +7,10 @@ import type {
7
7
  import { z } from 'zod'
8
8
 
9
9
  import { zodCaseInsensitiveEnum } from '../../lib/zodInputSemantics.ts'
10
+ import {
11
+ documentConvertLoadInternalErrorReason,
12
+ documentConvertLoadUserErrorReason,
13
+ } from '../responseErrors/DocumentConvertRobot.ts'
10
14
  import {
11
15
  createProcessingExample,
12
16
  defineRobot,
@@ -15,11 +19,24 @@ import {
15
19
  robotUse,
16
20
  } from './_instructions-primitives.ts'
17
21
 
22
+ const transcriptSrtDocumentation =
23
+ 'Timestamped JSON from `/speech/transcribe` with `"format": "json"` can be converted to SRT. ' +
24
+ 'Set `"format": "srt"` here. JSON words are grouped into cues of up to three words, breaking ' +
25
+ 'at sentence endings and pauses longer than 0.4 seconds. Casing and punctuation are preserved. ' +
26
+ 'JSON input is limited to 32 MiB and is only supported for SRT output. ' +
27
+ 'SRT-to-SRT copies the original cues unchanged.'
28
+
18
29
  /** Accepts Playwright's paper-format case variants while publishing canonical spellings. */
19
30
  export const documentConvertPdfFormatSchema = zodCaseInsensitiveEnum(
20
31
  z.enum(['A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'Ledger', 'Legal', 'Letter', 'Tabloid']),
21
32
  )
22
33
 
34
+ const documentLoadErrorDocumentation = `
35
+ A generic LibreOffice load refusal returns \`USER_COMMAND_ERROR\` with the reason “${documentConvertLoadUserErrorReason}” This preserves the user error code for integrations without assuming the document is corrupt.
36
+
37
+ When diagnostics identify a problem in the conversion service, the load failure returns \`INTERNAL_COMMAND_ERROR\` with the reason “${documentConvertLoadInternalErrorReason}” Private diagnostics are not included in either response.
38
+ `
39
+
23
40
  export const meta: RobotMetaInput = {
24
41
  ...robotDocumentProcessingMeta,
25
42
  example_code: createProcessingExample('converted', '/document/convert', {
@@ -37,6 +54,10 @@ Using this <dfn>Robot</dfn>, you can bypass the issues that certain file types m
37
54
  > ![Warning]
38
55
  > A general rule of this <dfn>Robot</dfn> is that converting files into an alien format category will result in an error. For example, SRT files can be converted into the VTT format, but not to an image.
39
56
 
57
+ ${documentLoadErrorDocumentation}
58
+
59
+ ${transcriptSrtDocumentation}
60
+
40
61
  The following file formats can be converted from:
41
62
 
42
63
  - \`ai\`
@@ -108,6 +129,10 @@ Using this Robot, you can bypass the issues that certain file types may bring, b
108
129
  > [!Warning]
109
130
  > A general rule of this Robot is that converting files into an alien format category will result in an error. For example, SRT files can be converted into the VTT format (and vice versa), but not to an image.
110
131
 
132
+ ${documentLoadErrorDocumentation}
133
+
134
+ ${transcriptSrtDocumentation}
135
+
111
136
  The following file formats can be converted from:
112
137
 
113
138
  - \`ai\`
@@ -10,6 +10,7 @@ import { ecmaWhitespaceCharacterClass } from '../../lib/zodInputSemantics.ts'
10
10
  import {
11
11
  createProcessingExample,
12
12
  defineRobot,
13
+ interpolationSchemaFull,
13
14
  robotBase,
14
15
  robotDocumentProcessingMeta,
15
16
  robotUse,
@@ -22,6 +23,81 @@ const textFormats = z.enum(['txt', 'json'])
22
23
  const textGranularities = z.enum(['document', 'page'])
23
24
  const textMethods = z.enum(['native', 'ocr', 'auto'])
24
25
 
26
+ /** Validate OCR dependencies after interpolation-aware parsing at the Assembly Step boundary. */
27
+ export function refineDocumentExtractOcr(
28
+ step: {
29
+ robot: string
30
+ extract?: unknown
31
+ text_method?: unknown
32
+ ocr_provider?: unknown
33
+ password?: unknown
34
+ page_range?: unknown
35
+ text_granularity?: unknown
36
+ },
37
+ context: z.RefinementCtx,
38
+ options: { allowInterpolation?: boolean } = {},
39
+ ): void {
40
+ if (step.robot !== '/document/extract') return
41
+ if (step.text_method !== 'ocr' && step.text_method !== 'auto') return
42
+
43
+ // Image-only extraction never invokes OCR; unresolved targets are checked at runtime.
44
+ const extractsText =
45
+ step.extract === undefined ||
46
+ step.extract === 'text' ||
47
+ (Array.isArray(step.extract) && step.extract.includes('text'))
48
+ if (!extractsText) return
49
+
50
+ if (step.ocr_provider === undefined) {
51
+ context.addIssue({
52
+ code: z.ZodIssueCode.custom,
53
+ path: ['ocr_provider'],
54
+ message: 'The ocr_provider parameter is required when text_method is ocr or auto.',
55
+ })
56
+ }
57
+
58
+ // Assembly Steps preserve opaque interpolation until the Robot checks the resolved values.
59
+ // Builtin fields can opt out because those values are already resolved at their boundary.
60
+ // Keep these constraints aligned with the matching stepJsonInputSchema branch in template.ts.
61
+ if (
62
+ step.password !== undefined &&
63
+ step.password !== '' &&
64
+ !(
65
+ options.allowInterpolation !== false &&
66
+ interpolationSchemaFull.safeParse(step.password).success
67
+ )
68
+ ) {
69
+ context.addIssue({
70
+ code: z.ZodIssueCode.custom,
71
+ path: ['password'],
72
+ message:
73
+ 'The password parameter is only supported for native text extraction and embedded image extraction.',
74
+ })
75
+ }
76
+
77
+ // Defer full page-range interpolation to runtime, consistently with the other unresolved fields.
78
+ if (
79
+ step.page_range !== undefined &&
80
+ !(
81
+ options.allowInterpolation !== false &&
82
+ interpolationSchemaFull.safeParse(step.page_range).success
83
+ )
84
+ ) {
85
+ context.addIssue({
86
+ code: z.ZodIssueCode.custom,
87
+ path: ['page_range'],
88
+ message: 'The page_range parameter is only supported for native text extraction.',
89
+ })
90
+ }
91
+
92
+ if (step.text_granularity === 'page') {
93
+ context.addIssue({
94
+ code: z.ZodIssueCode.custom,
95
+ path: ['text_granularity'],
96
+ message: 'The page text_granularity is only supported for native text extraction.',
97
+ })
98
+ }
99
+ }
100
+
25
101
  export const meta: RobotMetaInput = {
26
102
  ...robotDocumentProcessingMeta,
27
103
  example_code: createProcessingExample('extracted', '/document/extract', {
@@ -57,6 +57,7 @@ Use [🤖/image/resize](/docs/robots/image-resize/) to resize or crop the screen
57
57
  .default(null)
58
58
  .describe(`
59
59
  The URL of the web page to be converted. Optional, as you can also upload/import HTML files and pass it to this <dfn>Robot</dfn>.
60
+ Omit it, or use \`null\` or an empty string, to convert uploaded HTML instead.
60
61
  `),
61
62
  format: z
62
63
  .enum(['jpeg', 'jpg', 'pdf', 'png'])
@@ -6,6 +6,7 @@ import type {
6
6
 
7
7
  import { z } from 'zod'
8
8
 
9
+ import { zodWithConservativeJsonInputSchema } from '../../lib/zodInputSemantics.ts'
9
10
  import {
10
11
  autoProviderDescription,
11
12
  createProcessingExample,
@@ -21,6 +22,29 @@ const speechTranscribeProviderWithHiddenFieldsSchema = z
21
22
  .enum(['auto', 'aws', 'gcp', 'replicate', 'transloadit'])
22
23
  .default('auto')
23
24
 
25
+ /** Shared vocabulary limits keep inline hints within GCP and Whisper prompt budgets. */
26
+ export const speechTranscribeVocabularySchema = zodWithConservativeJsonInputSchema(
27
+ z
28
+ .array(
29
+ z
30
+ .string()
31
+ .trim()
32
+ .min(1)
33
+ .max(100)
34
+ .regex(/^[^\p{Cc}]+$/u),
35
+ )
36
+ .max(50)
37
+ .refine((terms) => new Set(terms.map((term) => term.toLowerCase())).size === terms.length, {
38
+ message: 'Vocabulary terms must be unique, ignoring case.',
39
+ })
40
+ // Byte-level tokenization uses at most one token per byte. Reserve room for sentence styling.
41
+ .refine((terms) => new TextEncoder().encode(terms.join(', ')).byteLength <= 200, {
42
+ message: 'Vocabulary terms joined with comma-space must not exceed 200 UTF-8 bytes.',
43
+ }),
44
+ // Trimming, Unicode case uniqueness and a joined UTF-8 budget have no portable JSON Schema form.
45
+ z.array(z.string().min(1)).max(50),
46
+ )
47
+
24
48
  export const meta: RobotMetaInput = {
25
49
  ...robotArtificialIntelligenceMeta,
26
50
  example_code: createProcessingExample('transcribed', '/speech/transcribe', {
@@ -77,7 +101,8 @@ recurring speakers:
77
101
  \`\`\`
78
102
 
79
103
  Speaker labels are currently supported by the \`aws\` and \`gcp\` providers. If you enable
80
- \`speaker_labels\` without setting \`provider\`, Transloadit uses \`aws\` for that <dfn>Step</dfn>. Labels
104
+ \`speaker_labels\` without setting \`provider\`, Transloadit uses \`aws\` for that <dfn>Step</dfn>, or
105
+ \`gcp\` when \`vocabulary\` is also supplied. Labels
81
106
  are normalized as \`speaker_1\`, \`speaker_2\`, and so on:
82
107
 
83
108
  \`\`\`json
@@ -100,7 +125,27 @@ ${autoProviderDescription}
100
125
 
101
126
  Set this to \`"aws"\`, \`"gcp"\`, or \`"replicate"\` to force a specific provider.
102
127
  When set to \`"auto"\`, Transloadit uses \`"replicate"\` by default and uses \`"aws"\` when
103
- \`speaker_labels\` is enabled.
128
+ \`speaker_labels\` is enabled. If both \`speaker_labels\` and a nonempty \`vocabulary\` are set,
129
+ \`"auto"\` uses \`"gcp"\`.
130
+ `),
131
+ vocabulary: speechTranscribeVocabularySchema.optional().describe(`
132
+ Words or phrases to favor during speech recognition, using the spelling you want in the output.
133
+ For example, \`["Transloadit", "Uppy", "tus"]\` helps the provider recognize brand and product names.
134
+
135
+ Supply up to 50 distinct terms, each between 1 and 100 characters after trimming surrounding
136
+ whitespace. Terms must not contain control characters or case-insensitive duplicates. The terms
137
+ joined with \`", "\` must fit within 200 UTF-8 bytes, keeping all terms within Whisper’s prompt
138
+ budget. Omitting this parameter or supplying an empty array leaves recognition unchanged.
139
+
140
+ Supported by \`"replicate"\` and \`"gcp"\`. Replicate uses a prompt-capable WhisperX large-v3 model
141
+ with aligned word timestamps when vocabulary is supplied. GCP uses inline boosted phrase hints.
142
+ Explicit \`"aws"\` requests with vocabulary return a validation error because AWS requires a
143
+ pre-created Custom Vocabulary. Use \`"auto"\`, \`"replicate"\`, or \`"gcp"\` instead.
144
+
145
+ Hints improve recognition but do not guarantee that a term is recognized. Afterwards, complete
146
+ case-insensitive matches use your supplied spelling in every output format, including JSON words
147
+ and speaker segments, without changing timestamps. Similar-sounding words are never replaced:
148
+ \`"transloadit"\` becomes \`"Transloadit"\`, but \`"Transloaded"\` stays unchanged.
104
149
  `),
105
150
  granularity: granularitySchema.describe(`
106
151
  Both \`"full"\` and \`"list"\` currently return the same complete transcription response. \`"list"\` remains accepted for backward compatibility.
@@ -36,7 +36,8 @@ export const meta: RobotMetaInput = {
36
36
  name: 'VideoSplitRobot',
37
37
  }
38
38
 
39
- const segmentSchema = z
39
+ /** A reusable clip window with the same time values accepted by video splitting. */
40
+ export const segmentSchema = z
40
41
  .object({
41
42
  from: z
42
43
  .union([z.number(), z.string()])
@@ -59,7 +59,7 @@ export const meta: RobotMetaInput = {
59
59
  },
60
60
  },
61
61
  example_code_description:
62
- 'Transcribe an uploaded video into timestamped words, then burn in uppercase social captions with the spoken word highlighted. Captions normally contain up to three words, breaking at sentence endings and pauses longer than 0.4 seconds. A trailing function word can move to the next caption, allowing one extra word there:',
62
+ 'Transcribe an uploaded video into timestamped words, then burn in uppercase social captions with the spoken word highlighted. Captions normally contain up to three words, breaking at sentence endings and pauses longer than 0.4 seconds. Social phrasing can use one extra word to keep a short phrase together or avoid a sentence-final orphan:',
63
63
  purpose_sentence: 'adds subtitles and closed captions to videos',
64
64
  purpose_verb: 'subtitle',
65
65
  purpose_word: 'subtitle',
@@ -89,7 +89,7 @@ Determines if subtitles are added as a separate stream to the video (value \`"ex
89
89
  .enum(['social'])
90
90
  .optional()
91
91
  .describe(`
92
- Applies a ready-made appearance for burned subtitles: heavy Poppins text and a large font scaled with the video height. JSON captions render in uppercase in the lower third with a thick outline and a soft black shadow. Each caption grows from 85% to full size over 120 milliseconds, then its words stay in place while the highlight changes color. The transcript file is preserved. Existing styling parameters override the preset. ASS files retain their own styles. With timestamped JSON from \`/speech/transcribe\`, the active word is highlighted until the next word or caption starts; other words use \`font_color\`. Trailing commas and periods are omitted from social JSON captions; question marks and exclamation marks are preserved. Word highlighting and grouping require JSON input.
92
+ Applies a ready-made appearance for burned subtitles: heavy Poppins text, a thick outline, and a soft black shadow. JSON captions render in uppercase in the lower third. By default, JSON font sizing uses the shorter side of the video and fits each caption within the safe width, preferring one line and using at most two. Words are never split. Each caption grows from 85% to full size over 120 milliseconds, then its words stay in place while the highlight changes color. The transcript file is preserved. Existing styling parameters override the preset; an explicit \`font_size\` disables automatic fitting. ASS files retain their own styles. With timestamped JSON from \`/speech/transcribe\`, the active word is highlighted until the next word or caption starts; other words use \`font_color\`. Trailing commas and periods are omitted from social JSON captions; question marks and exclamation marks are preserved. Word highlighting and grouping require JSON input.
93
93
  `),
94
94
  highlight_color: subtitleColorSchema.default('FFD60A').describe(`
95
95
  The accent color of the active word in JSON subtitles. Only applies to burned JSON subtitles. With \`"style": "social"\`, the previous word stays highlighted through short gaps until the next word or caption starts. Without the social style, gaps use \`font_color\` for the entire caption.
@@ -102,7 +102,7 @@ ${subtitleColorDescription}
102
102
  .min(1)
103
103
  .default(3)
104
104
  .describe(`
105
- The target maximum number of timestamped JSON words shown in a caption. Captions break earlier at sentence-ending punctuation or pauses longer than 0.4 seconds. With \`"style": "social"\`, a trailing English function word such as “by,” “to,” or “the” moves to the next caption when possible, allowing at most one extra word in that caption. Single-word captions are preserved when the limit is 1. A caption stays visible until the next caption starts when the pause is at most 0.4 seconds, and disappears at its last word’s end during longer pauses. Does not change SRT, VTT, or ASS cues.
105
+ The target maximum number of timestamped JSON words shown in a caption. Captions break earlier at sentence-ending punctuation or pauses longer than 0.4 seconds. With \`"style": "social"\`, a trailing English function word such as “by,” “to,” or “the” moves to the next caption when possible. Short phrases such as “line of code” can stay together, and a sentence-final single word can join the previous caption. These adjustments allow at most one extra word per caption, without crossing sentence endings or long pauses. Single-word captions are preserved when the limit is 1. A caption stays visible until the next caption starts when the pause is at most 0.4 seconds, and disappears at its last word’s end during longer pauses. Does not change SRT, VTT, or ASS cues.
106
106
  `),
107
107
  border_style: z
108
108
  .enum(['box', 'outline', 'shadow'])
@@ -115,12 +115,13 @@ The color for the subtitle border. The default is opaque black. Only applies to
115
115
 
116
116
  ${subtitleColorDescription}
117
117
  `),
118
+ // Preserve omitted appearance fields so parsing cannot override the selected style's defaults.
118
119
  // TODO: Make font an enum
119
120
  font: z
120
121
  .string()
121
- .default('Arial')
122
+ .optional()
122
123
  .describe(`
123
- The font family to use. Also includes boldness and style of the font. With \`"style": "social"\`, the default is Poppins, using its ExtraBold weight for JSON captions. An explicit font overrides the style.
124
+ The font family to use. Also includes boldness and style of the font. The default is Arial. With \`"style": "social"\`, the default is ${videoSubtitleSocialStyle.font}, using its ExtraBold weight for JSON captions. An explicit font overrides the style.
124
125
 
125
126
  [Here](/docs/supported-formats/fonts/) is a list of all supported fonts.
126
127
  `),
@@ -133,15 +134,15 @@ ${subtitleColorDescription}
133
134
  .number()
134
135
  .int()
135
136
  .min(1)
136
- .default(16)
137
+ .optional()
137
138
  .describe(`
138
- Specifies the size of the text in the 288-pixel subtitle coordinate space, scaled with the video height. With \`"style": "social"\`, the default is 54. Poppins capital letters are about 7.5% of the video height at this size. An explicit value overrides the style.
139
+ Specifies the size of the text in the 288-pixel subtitle coordinate space, scaled with the video height. The default is 16. With \`"style": "social"\`, the default is ${videoSubtitleSocialStyle.font_size}. For social JSON captions, an omitted value scales this default with the shorter side of the video, increases it by 18% for portrait video, and shrinks captions as needed to fit at most two lines. Poppins capital letters are about 7.5% of the shorter side before fitting, or about 9% for portrait video. An explicit value keeps height-relative sizing and disables automatic fitting.
139
140
  `),
140
141
  bold: z
141
142
  .boolean()
142
- .default(false)
143
+ .optional()
143
144
  .describe(`
144
- Specifies whether the subtitle text should be bold. Only applies to burned subtitles. With \`"style": "social"\`, the default is \`true\`; an explicit \`false\` overrides the style.
145
+ Specifies whether the subtitle text should be bold. Only applies to burned subtitles. The default is \`false\`. With \`"style": "social"\`, the default is \`${videoSubtitleSocialStyle.bold}\`; an explicit \`false\` overrides the style.
145
146
  `),
146
147
  italic: z
147
148
  .boolean()
@@ -157,10 +158,10 @@ Specifies whether the subtitle text should be italic. Only applies to burned sub
157
158
  .optional()
158
159
  .nullable()
159
160
  .describe(`
160
- Specifies the width of the text outline in the 288-pixel subtitle coordinate space, scaled with the video height. Numeric strings such as \`"4"\` are also accepted. Only applies to burned subtitles with \`"outline"\` or \`"box"\` border styles. If omitted or \`null\`, the default width is used (2 with \`"style": "social"\`, about 3.7 pixels on a video 534 pixels high).
161
+ Specifies the width of the text outline in the 288-pixel subtitle coordinate space, scaled with the video height. Numeric strings such as \`"4"\` are also accepted. Only applies to burned subtitles with \`"outline"\` or \`"box"\` border styles. If omitted or \`null\`, the default width is used (2 with \`"style": "social"\`, proportional to the final fitted font size for social JSON captions).
161
162
  `),
162
163
  position: positionSchema.default('bottom').describe(`
163
- Specifies the position of the subtitles. With \`"style": "social"\`, the default bottom position places JSON captions in the lower third. An explicit value overrides the style.
164
+ Specifies the position of the subtitles. With \`"style": "social"\`, the default bottom position places JSON captions in the lower third, with extra bottom clearance on portrait video. An explicit value overrides the style.
164
165
  `),
165
166
  language: z
166
167
  .string()
@@ -94,7 +94,8 @@ The thumbnails are taken at regular intervals, determined by dividing the video
94
94
  To extract thumbnails for specific timestamps, use the \`offsets\` parameter.
95
95
  `),
96
96
  offsets: z
97
- .union([z.array(z.number()), z.array(percentageSchema)])
97
+ .union([z.array(z.number().finite()), z.array(percentageSchema)])
98
+ .nullable()
98
99
  .default([])
99
100
  .describe(`
100
101
  An array of offsets representing seconds of the file duration, such as \`[ 2, 45, 120 ]\`. Millisecond durations of a file can also be used by using decimal place values. For example, an offset from 1250 milliseconds would be represented with \`1.25\`. Offsets can also be percentage values such as \`[ "2%", "50%", "75%" ]\`.
@@ -102,6 +103,8 @@ An array of offsets representing seconds of the file duration, such as \`[ 2, 45
102
103
  This option cannot be used with the \`count\` parameter, and takes precedence if both are specified. Out-of-range offsets are silently ignored.
103
104
 
104
105
  When \`smart\` is \`true\`, smart selection ignores \`offsets\` and uses \`count\` to select from its own candidate timestamps. If no smart candidates can be extracted, the Robot falls back to standard extraction, where \`offsets\` takes precedence. Use \`smart: false\` to consistently extract the specified timestamps.
106
+
107
+ Use \`null\` to leave timestamp selection to \`count\` and \`smart\`.
105
108
  `),
106
109
  format: z
107
110
  .enum(['jpeg', 'jpg', 'png'])
@@ -114,18 +117,20 @@ The format of the extracted thumbnail. Supported values are \`"jpg"\`, \`"jpeg"\
114
117
  .int()
115
118
  .min(1)
116
119
  .max(1920)
120
+ .nullable()
117
121
  .optional()
118
122
  .describe(`
119
- The width of the thumbnail, in pixels. Defaults to the original width of the video.
123
+ The width of the thumbnail, in pixels. Omit or use \`null\` for the original width of the video.
120
124
  `),
121
125
  height: z
122
126
  .number()
123
127
  .int()
124
128
  .min(1)
125
129
  .max(1080)
130
+ .nullable()
126
131
  .optional()
127
132
  .describe(`
128
- The height of the thumbnail, in pixels. Defaults to the original height of the video.
133
+ The height of the thumbnail, in pixels. Omit or use \`null\` for the original height of the video.
129
134
  `),
130
135
  resize_strategy: resize_strategy.describe(`
131
136
  One of the [available resize strategies](/docs/topics/resize-strategies/).
@@ -9,6 +9,7 @@ import type {
9
9
  RobotsWithHiddenBotsAndFields,
10
10
  } from './robots/_index.ts'
11
11
  import type { RobotUse } from './robots/_instructions-primitives.ts'
12
+ import { refineDocumentExtractOcr } from './robots/document-extract.ts'
12
13
  import { refineTransloaditImportSelector } from './robots/transloadit-import.ts'
13
14
 
14
15
  export type Step = RobotsSchema
@@ -26,6 +27,7 @@ export const stepSchema: z.ZodType<Step> = z
26
27
  })
27
28
  .and(robotsSchema)
28
29
  .superRefine(refineTransloaditImportSelector)
30
+ .superRefine(refineDocumentExtractOcr)
29
31
  export const stepsSchema: z.ZodType<Steps> = z
30
32
  .record(stepSchema)
31
33
  .describe('Contains Assembly Instructions.')
@@ -45,6 +47,7 @@ export const stepSchemaWithHiddenFields: z.ZodType<StepWithHiddenFields> = z
45
47
  })
46
48
  .and(robotsWithHiddenBotsAndFieldsSchema)
47
49
  .superRefine(refineTransloaditImportSelector)
50
+ .superRefine(refineDocumentExtractOcr)
48
51
  export const stepsSchemaWithHiddenFields: z.ZodType<StepsWithHiddenFields> = z
49
52
  .record(stepSchemaWithHiddenFields)
50
53
  .describe('Contains Assembly Instructions.')
@@ -227,7 +227,7 @@ export async function replay(
227
227
  ): Promise<void> {
228
228
  if (steps) {
229
229
  try {
230
- await apiCall(await readStepsInputFile(steps))
230
+ await apiCall(await readStepsInputFile(steps, output))
231
231
  } catch (err) {
232
232
  const error = ensureError(err)
233
233
  output.error(error.message)
@@ -1353,7 +1353,7 @@ export async function create(
1353
1353
  // to avoid zod adding default values that the API may reject
1354
1354
  let effectiveStepsData = stepsData
1355
1355
  if (steps) {
1356
- effectiveStepsData = await readStepsInputFile(steps)
1356
+ effectiveStepsData = await readStepsInputFile(steps, outputctl)
1357
1357
  }
1358
1358
 
1359
1359
  // Determine output stat async before entering the Promise constructor
@@ -2018,7 +2018,7 @@ export class RunCommand extends AuthenticatedCommand {
2018
2018
  }
2019
2019
 
2020
2020
  const { hasFailures, resultUrls } = await create(this.output, this.client, {
2021
- stepsData: parseStepsInputJson(JSON.stringify(compiled.instructions.steps)),
2021
+ stepsData: parseStepsInputJson(JSON.stringify(compiled.instructions.steps), this.output),
2022
2022
  fields: fieldsMap ?? {},
2023
2023
  watch: this.watch,
2024
2024
  recursive: this.recursive,