@transloadit/node 4.1.9 → 4.3.0
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.
- package/README.md +81 -1
- package/dist/Transloadit.d.ts +36 -5
- package/dist/Transloadit.d.ts.map +1 -1
- package/dist/Transloadit.js +228 -39
- package/dist/Transloadit.js.map +1 -1
- package/dist/alphalib/assembly-linter.d.ts +123 -0
- package/dist/alphalib/assembly-linter.d.ts.map +1 -0
- package/dist/alphalib/assembly-linter.js +1142 -0
- package/dist/alphalib/assembly-linter.js.map +1 -0
- package/dist/alphalib/assembly-linter.lang.en.d.ts +87 -0
- package/dist/alphalib/assembly-linter.lang.en.d.ts.map +1 -0
- package/dist/alphalib/assembly-linter.lang.en.js +326 -0
- package/dist/alphalib/assembly-linter.lang.en.js.map +1 -0
- package/dist/alphalib/mcache.d.ts.map +1 -1
- package/dist/alphalib/mcache.js +22 -7
- package/dist/alphalib/mcache.js.map +1 -1
- package/dist/alphalib/object.d.ts +20 -0
- package/dist/alphalib/object.d.ts.map +1 -0
- package/dist/alphalib/object.js +23 -0
- package/dist/alphalib/object.js.map +1 -0
- package/dist/alphalib/stepParsing.d.ts +93 -0
- package/dist/alphalib/stepParsing.d.ts.map +1 -0
- package/dist/alphalib/stepParsing.js +1154 -0
- package/dist/alphalib/stepParsing.js.map +1 -0
- package/dist/alphalib/templateMerge.d.ts +4 -0
- package/dist/alphalib/templateMerge.d.ts.map +1 -0
- package/dist/alphalib/templateMerge.js +22 -0
- package/dist/alphalib/templateMerge.js.map +1 -0
- package/dist/alphalib/types/assemblyReplay.d.ts +56 -0
- package/dist/alphalib/types/assemblyReplay.d.ts.map +1 -1
- package/dist/alphalib/types/assemblyReplayNotification.d.ts +56 -0
- package/dist/alphalib/types/assemblyReplayNotification.d.ts.map +1 -1
- package/dist/alphalib/types/assemblyStatus.d.ts +63 -57
- package/dist/alphalib/types/assemblyStatus.d.ts.map +1 -1
- package/dist/alphalib/types/assemblyStatus.js +9 -1
- package/dist/alphalib/types/assemblyStatus.js.map +1 -1
- package/dist/alphalib/types/assemblyUrls.d.ts +1 -1
- package/dist/alphalib/types/assemblyUrls.d.ts.map +1 -1
- package/dist/alphalib/types/assemblyUrls.js.map +1 -1
- package/dist/alphalib/types/robots/_index.d.ts +608 -81
- package/dist/alphalib/types/robots/_index.d.ts.map +1 -1
- package/dist/alphalib/types/robots/_index.js +4 -0
- package/dist/alphalib/types/robots/_index.js.map +1 -1
- package/dist/alphalib/types/robots/_instructions-primitives.d.ts +4 -4
- package/dist/alphalib/types/robots/_instructions-primitives.d.ts.map +1 -1
- package/dist/alphalib/types/robots/_instructions-primitives.js +1 -0
- package/dist/alphalib/types/robots/_instructions-primitives.js.map +1 -1
- package/dist/alphalib/types/robots/document-optimize.d.ts +489 -0
- package/dist/alphalib/types/robots/document-optimize.d.ts.map +1 -0
- package/dist/alphalib/types/robots/document-optimize.js +151 -0
- package/dist/alphalib/types/robots/document-optimize.js.map +1 -0
- package/dist/alphalib/types/template.d.ts +1050 -174
- package/dist/alphalib/types/template.d.ts.map +1 -1
- package/dist/cli/commands/assemblies.d.ts +20 -1
- package/dist/cli/commands/assemblies.d.ts.map +1 -1
- package/dist/cli/commands/assemblies.js +137 -2
- package/dist/cli/commands/assemblies.js.map +1 -1
- package/dist/cli/commands/auth.d.ts.map +1 -1
- package/dist/cli/commands/auth.js +19 -19
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +2 -1
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/docs/assemblyLintingExamples.d.ts +2 -0
- package/dist/cli/docs/assemblyLintingExamples.d.ts.map +1 -0
- package/dist/cli/docs/assemblyLintingExamples.js +10 -0
- package/dist/cli/docs/assemblyLintingExamples.js.map +1 -0
- package/dist/cli/helpers.d.ts +11 -0
- package/dist/cli/helpers.d.ts.map +1 -1
- package/dist/cli/helpers.js +29 -0
- package/dist/cli/helpers.js.map +1 -1
- package/dist/lintAssemblyInput.d.ts +10 -0
- package/dist/lintAssemblyInput.d.ts.map +1 -0
- package/dist/lintAssemblyInput.js +73 -0
- package/dist/lintAssemblyInput.js.map +1 -0
- package/dist/lintAssemblyInstructions.d.ts +29 -0
- package/dist/lintAssemblyInstructions.d.ts.map +1 -0
- package/dist/lintAssemblyInstructions.js +33 -0
- package/dist/lintAssemblyInstructions.js.map +1 -0
- package/dist/tus.d.ts +2 -1
- package/dist/tus.d.ts.map +1 -1
- package/dist/tus.js +2 -1
- package/dist/tus.js.map +1 -1
- package/package.json +5 -2
- package/src/Transloadit.ts +318 -49
- package/src/alphalib/assembly-linter.lang.en.ts +393 -0
- package/src/alphalib/assembly-linter.ts +1475 -0
- package/src/alphalib/mcache.ts +26 -7
- package/src/alphalib/object.ts +27 -0
- package/src/alphalib/stepParsing.ts +1465 -0
- package/src/alphalib/templateMerge.ts +32 -0
- package/src/alphalib/types/assemblyStatus.ts +9 -1
- package/src/alphalib/types/assemblyUrls.ts +2 -5
- package/src/alphalib/types/robots/_index.ts +14 -0
- package/src/alphalib/types/robots/_instructions-primitives.ts +1 -0
- package/src/alphalib/types/robots/document-optimize.ts +180 -0
- package/src/alphalib/typings/json-to-ast.d.ts +34 -0
- package/src/cli/commands/assemblies.ts +161 -2
- package/src/cli/commands/auth.ts +19 -22
- package/src/cli/commands/index.ts +2 -0
- package/src/cli/docs/assemblyLintingExamples.ts +9 -0
- package/src/cli/helpers.ts +50 -0
- package/src/lintAssemblyInput.ts +89 -0
- package/src/lintAssemblyInstructions.ts +72 -0
- package/src/tus.ts +3 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import merge from 'lodash-es/merge.js'
|
|
2
|
+
import type { ResponseTemplateContent, TemplateContent } from '../apiTypes.ts'
|
|
3
|
+
import type { AssemblyInstructionsInput } from './types/template.ts'
|
|
4
|
+
|
|
5
|
+
export function mergeTemplateContent(
|
|
6
|
+
template: TemplateContent | ResponseTemplateContent,
|
|
7
|
+
params?: AssemblyInstructionsInput,
|
|
8
|
+
): AssemblyInstructionsInput {
|
|
9
|
+
const templateContent = structuredClone(template) as TemplateContent | ResponseTemplateContent
|
|
10
|
+
const templateRecord = templateContent as Record<string, unknown>
|
|
11
|
+
|
|
12
|
+
if (templateContent.allow_steps_override == null) {
|
|
13
|
+
templateContent.allow_steps_override = true
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (params?.steps != null && templateContent.allow_steps_override === false) {
|
|
17
|
+
throw new Error('TEMPLATE_DENIES_STEPS_OVERRIDE')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (params == null) {
|
|
21
|
+
return templateContent as AssemblyInstructionsInput
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const paramsRecord = { ...params } as Record<string, unknown>
|
|
25
|
+
for (const key of Object.keys(templateRecord)) {
|
|
26
|
+
if (paramsRecord[key] === null && templateRecord[key] !== null) {
|
|
27
|
+
paramsRecord[key] = templateRecord[key]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return merge({}, templateRecord, paramsRecord) as AssemblyInstructionsInput
|
|
32
|
+
}
|
|
@@ -78,6 +78,8 @@ export const assemblyStatusErrCodeSchema = z.enum([
|
|
|
78
78
|
'DIGITALOCEAN_STORE_ACCESS_DENIED',
|
|
79
79
|
'DO_NOT_REUSE_ASSEMBLY_IDS',
|
|
80
80
|
'DOCUMENT_CONVERT_UNSUPPORTED_CONVERSION',
|
|
81
|
+
'DOCUMENT_OPTIMIZE_UNSUPPORTED_INPUT',
|
|
82
|
+
'DOCUMENT_OPTIMIZE_VALIDATION',
|
|
81
83
|
'DOCUMENT_SPLIT_VALIDATION',
|
|
82
84
|
'FILE_DOWNLOAD_ERROR',
|
|
83
85
|
'FILE_FILTER_DECLINED_FILE',
|
|
@@ -112,6 +114,7 @@ export const assemblyStatusErrCodeSchema = z.enum([
|
|
|
112
114
|
'INVALID_AUTH_REFERER_PARAMETER',
|
|
113
115
|
'INVALID_FILE_META_DATA',
|
|
114
116
|
'INVALID_FORM_DATA',
|
|
117
|
+
'INVALID_URL_ENCODING',
|
|
115
118
|
'INVALID_INPUT_ERROR',
|
|
116
119
|
'INVALID_PARAMS_FIELD',
|
|
117
120
|
'INVALID_SIGNATURE',
|
|
@@ -156,6 +159,9 @@ export const assemblyStatusErrCodeSchema = z.enum([
|
|
|
156
159
|
'TMP_FILE_DOWNLOAD_ERROR',
|
|
157
160
|
'USER_COMMAND_ERROR',
|
|
158
161
|
'VERIFIED_EMAIL_REQUIRED',
|
|
162
|
+
'VIDEO_CONCAT_INVALID_INPUT',
|
|
163
|
+
'VIDEO_CONCAT_NO_OUTPUT',
|
|
164
|
+
'VIDEO_CONCAT_VALIDATION',
|
|
159
165
|
'VIDEO_ENCODE_VALIDATION',
|
|
160
166
|
'VIMEO_IMPORT_FAILURE',
|
|
161
167
|
'WORKER_JOB_ERROR',
|
|
@@ -379,7 +385,7 @@ export const assemblyStatusUploadSchema = z
|
|
|
379
385
|
basename: z.string(),
|
|
380
386
|
ext: z.string(),
|
|
381
387
|
size: z.number(),
|
|
382
|
-
mime: z.string(),
|
|
388
|
+
mime: z.string().nullable(),
|
|
383
389
|
type: z.string().nullable(),
|
|
384
390
|
field: z.string().nullable(),
|
|
385
391
|
md5hash: z.string().nullable(),
|
|
@@ -614,6 +620,8 @@ export const assemblyStatusErrSchema = assemblyStatusBaseSchema
|
|
|
614
620
|
reason: z.string().optional(),
|
|
615
621
|
step: z.string().optional(),
|
|
616
622
|
previousStep: z.string().optional(),
|
|
623
|
+
file: z.string().optional(),
|
|
624
|
+
name: z.string().optional(),
|
|
617
625
|
path: z.string().optional(),
|
|
618
626
|
exitCode: z.number().nullable().optional(),
|
|
619
627
|
exitSignal: z.string().nullable().optional(),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import type { AssemblyStatus } from './assemblyStatus.ts'
|
|
1
2
|
import {
|
|
2
|
-
type AssemblyStatus,
|
|
3
3
|
isAssemblyBusyStatus,
|
|
4
4
|
isAssemblyTerminalError,
|
|
5
5
|
isAssemblyTerminalOk,
|
|
@@ -56,10 +56,7 @@ const assemblyUrlKeys = ['assembly_ssl_url', 'assembly_url', 'assemblyUrl'] as c
|
|
|
56
56
|
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
57
57
|
value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
58
58
|
|
|
59
|
-
const pickString = (
|
|
60
|
-
record: Record<string, unknown>,
|
|
61
|
-
keys: readonly string[],
|
|
62
|
-
): string | null => {
|
|
59
|
+
const pickString = (record: Record<string, unknown>, keys: readonly string[]): string | null => {
|
|
63
60
|
for (const key of keys) {
|
|
64
61
|
const value = record[key]
|
|
65
62
|
if (typeof value === 'string' && value.length > 0) return value
|
|
@@ -104,6 +104,11 @@ import {
|
|
|
104
104
|
interpolatableRobotDocumentOcrInstructionsSchema,
|
|
105
105
|
interpolatableRobotDocumentOcrInstructionsWithHiddenFieldsSchema,
|
|
106
106
|
} from './document-ocr.ts'
|
|
107
|
+
import {
|
|
108
|
+
meta as documentOptimizeMeta,
|
|
109
|
+
interpolatableRobotDocumentOptimizeInstructionsSchema,
|
|
110
|
+
interpolatableRobotDocumentOptimizeInstructionsWithHiddenFieldsSchema,
|
|
111
|
+
} from './document-optimize.ts'
|
|
107
112
|
import {
|
|
108
113
|
meta as documentSplitMeta,
|
|
109
114
|
interpolatableRobotDocumentSplitInstructionsSchema,
|
|
@@ -435,6 +440,7 @@ const robotStepsInstructions = [
|
|
|
435
440
|
interpolatableRobotDocumentConvertInstructionsSchema,
|
|
436
441
|
interpolatableRobotDocumentMergeInstructionsSchema,
|
|
437
442
|
interpolatableRobotDocumentOcrInstructionsSchema,
|
|
443
|
+
interpolatableRobotDocumentOptimizeInstructionsSchema,
|
|
438
444
|
interpolatableRobotFileReadInstructionsSchema,
|
|
439
445
|
interpolatableRobotDocumentSplitInstructionsSchema,
|
|
440
446
|
interpolatableRobotDocumentThumbsInstructionsSchema,
|
|
@@ -519,6 +525,7 @@ const robotStepsInstructionsWithHiddenFields = [
|
|
|
519
525
|
interpolatableRobotDocumentConvertInstructionsWithHiddenFieldsSchema,
|
|
520
526
|
interpolatableRobotDocumentMergeInstructionsWithHiddenFieldsSchema,
|
|
521
527
|
interpolatableRobotDocumentOcrInstructionsWithHiddenFieldsSchema,
|
|
528
|
+
interpolatableRobotDocumentOptimizeInstructionsWithHiddenFieldsSchema,
|
|
522
529
|
interpolatableRobotFileReadInstructionsWithHiddenFieldsSchema,
|
|
523
530
|
interpolatableRobotDocumentSplitInstructionsWithHiddenFieldsSchema,
|
|
524
531
|
interpolatableRobotDocumentThumbsInstructionsWithHiddenFieldsSchema,
|
|
@@ -632,6 +639,7 @@ export const robotsMeta = {
|
|
|
632
639
|
documentConvertMeta,
|
|
633
640
|
documentMergeMeta,
|
|
634
641
|
documentOcrMeta,
|
|
642
|
+
documentOptimizeMeta,
|
|
635
643
|
documentSplitMeta,
|
|
636
644
|
documentThumbsMeta,
|
|
637
645
|
dropboxImportMeta,
|
|
@@ -824,6 +832,12 @@ export type {
|
|
|
824
832
|
InterpolatableRobotDocumentOcrInstructionsWithHiddenFields,
|
|
825
833
|
InterpolatableRobotDocumentOcrInstructionsWithHiddenFieldsInput,
|
|
826
834
|
} from './document-ocr.ts'
|
|
835
|
+
export type {
|
|
836
|
+
InterpolatableRobotDocumentOptimizeInstructions,
|
|
837
|
+
InterpolatableRobotDocumentOptimizeInstructionsInput,
|
|
838
|
+
InterpolatableRobotDocumentOptimizeInstructionsWithHiddenFields,
|
|
839
|
+
InterpolatableRobotDocumentOptimizeInstructionsWithHiddenFieldsInput,
|
|
840
|
+
} from './document-optimize.ts'
|
|
827
841
|
export type {
|
|
828
842
|
InterpolatableRobotDocumentSplitInstructions,
|
|
829
843
|
InterpolatableRobotDocumentSplitInstructionsInput,
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
import type { RobotMetaInput } from './_instructions-primitives.ts'
|
|
4
|
+
import { interpolateRobot, robotBase, robotUse } from './_instructions-primitives.ts'
|
|
5
|
+
|
|
6
|
+
export const meta: RobotMetaInput = {
|
|
7
|
+
allowed_for_url_transform: true,
|
|
8
|
+
bytescount: 1,
|
|
9
|
+
discount_factor: 1,
|
|
10
|
+
discount_pct: 0,
|
|
11
|
+
example_code: {
|
|
12
|
+
steps: {
|
|
13
|
+
optimized: {
|
|
14
|
+
robot: '/document/optimize',
|
|
15
|
+
use: ':original',
|
|
16
|
+
preset: 'ebook',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
example_code_description: 'Optimize PDF file size using the ebook preset:',
|
|
21
|
+
extended_description: `
|
|
22
|
+
This <dfn>Robot</dfn> reduces PDF file sizes. It recompresses images, subsets fonts, and applies various optimizations to reduce file size while maintaining acceptable quality.
|
|
23
|
+
|
|
24
|
+
## Quality Presets
|
|
25
|
+
|
|
26
|
+
The Robot supports four quality presets that control the trade-off between file size and quality:
|
|
27
|
+
|
|
28
|
+
| Preset | DPI | Use Case | Typical Savings |
|
|
29
|
+
|--------|-----|----------|-----------------|
|
|
30
|
+
| \`screen\` | 72 | Screen viewing, smallest files | ~86% |
|
|
31
|
+
| \`ebook\` | 150 | Good balance of quality/size | ~71% |
|
|
32
|
+
| \`printer\` | 300 | Print quality | Moderate |
|
|
33
|
+
| \`prepress\` | Highest | Press-ready, largest files | Minimal |
|
|
34
|
+
|
|
35
|
+
## Use Cases
|
|
36
|
+
|
|
37
|
+
- Reducing storage costs for archived documents
|
|
38
|
+
- Faster document delivery and download
|
|
39
|
+
- Meeting email attachment size limits
|
|
40
|
+
- Mobile-optimized document viewing
|
|
41
|
+
`,
|
|
42
|
+
minimum_charge: 2097152,
|
|
43
|
+
output_factor: 0.5,
|
|
44
|
+
override_lvl1: 'Document Processing',
|
|
45
|
+
purpose_sentence: 'reduces the file size of PDF documents',
|
|
46
|
+
purpose_verb: 'optimize',
|
|
47
|
+
purpose_word: 'optimize PDF',
|
|
48
|
+
purpose_words: 'Optimize PDF file size',
|
|
49
|
+
service_slug: 'document-processing',
|
|
50
|
+
slot_count: 10,
|
|
51
|
+
title: 'Reduce PDF file size',
|
|
52
|
+
typical_file_size_mb: 2.0,
|
|
53
|
+
typical_file_type: 'document',
|
|
54
|
+
name: 'DocumentOptimizeRobot',
|
|
55
|
+
priceFactor: 1,
|
|
56
|
+
queueSlotCount: 10,
|
|
57
|
+
minimumCharge: 2097152,
|
|
58
|
+
isAllowedForUrlTransform: true,
|
|
59
|
+
trackOutputFileSize: true,
|
|
60
|
+
isInternal: false,
|
|
61
|
+
removeJobResultFilesFromDiskRightAfterStoringOnS3: false,
|
|
62
|
+
stage: 'beta',
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export const robotDocumentOptimizeInstructionsSchema = robotBase
|
|
66
|
+
.merge(robotUse)
|
|
67
|
+
.extend({
|
|
68
|
+
robot: z.literal('/document/optimize').describe(`
|
|
69
|
+
This Robot reduces PDF file sizes. It recompresses images, subsets fonts, and applies various optimizations to reduce file size while maintaining acceptable quality.
|
|
70
|
+
|
|
71
|
+
## Quality Presets
|
|
72
|
+
|
|
73
|
+
The Robot supports four quality presets that control the trade-off between file size and quality:
|
|
74
|
+
|
|
75
|
+
| Preset | DPI | Use Case | Typical Savings |
|
|
76
|
+
|--------|-----|----------|-----------------|
|
|
77
|
+
| \`screen\` | 72 | Screen viewing, smallest files | ~86% |
|
|
78
|
+
| \`ebook\` | 150 | Good balance of quality/size | ~71% |
|
|
79
|
+
| \`printer\` | 300 | Print quality | Moderate |
|
|
80
|
+
| \`prepress\` | Highest | Press-ready, largest files | Minimal |
|
|
81
|
+
`),
|
|
82
|
+
preset: z
|
|
83
|
+
.enum(['screen', 'ebook', 'printer', 'prepress'])
|
|
84
|
+
.default('ebook')
|
|
85
|
+
.describe(`
|
|
86
|
+
The quality preset to use for optimization. Each preset provides a different balance between file size and quality:
|
|
87
|
+
|
|
88
|
+
- \`screen\` - Lowest quality, smallest file size. Best for screen viewing only. Images are downsampled to 72 DPI.
|
|
89
|
+
- \`ebook\` - Good balance of quality and size. Suitable for most purposes. Images are downsampled to 150 DPI.
|
|
90
|
+
- \`printer\` - High quality suitable for printing. Images are kept at 300 DPI.
|
|
91
|
+
- \`prepress\` - Highest quality for professional printing. Minimal compression applied.
|
|
92
|
+
`),
|
|
93
|
+
image_dpi: z
|
|
94
|
+
.number()
|
|
95
|
+
.int()
|
|
96
|
+
.min(36)
|
|
97
|
+
.max(600)
|
|
98
|
+
.optional()
|
|
99
|
+
.describe(`
|
|
100
|
+
Target DPI (dots per inch) for embedded images. When specified, this overrides the DPI setting from the preset.
|
|
101
|
+
|
|
102
|
+
Higher DPI values result in better image quality but larger file sizes. Lower values produce smaller files but may result in pixelated images when printed.
|
|
103
|
+
|
|
104
|
+
Common values:
|
|
105
|
+
- 72 - Screen viewing
|
|
106
|
+
- 150 - eBooks and general documents
|
|
107
|
+
- 300 - Print quality
|
|
108
|
+
- 600 - High-quality print
|
|
109
|
+
`),
|
|
110
|
+
compress_fonts: z
|
|
111
|
+
.boolean()
|
|
112
|
+
.default(true)
|
|
113
|
+
.describe(`
|
|
114
|
+
Whether to compress embedded fonts. When enabled, fonts are compressed to reduce file size.
|
|
115
|
+
`),
|
|
116
|
+
subset_fonts: z
|
|
117
|
+
.boolean()
|
|
118
|
+
.default(true)
|
|
119
|
+
.describe(`
|
|
120
|
+
Whether to subset embedded fonts, keeping only the glyphs that are actually used in the document. This can significantly reduce file size for documents that only use a small portion of a font's character set.
|
|
121
|
+
`),
|
|
122
|
+
remove_metadata: z
|
|
123
|
+
.boolean()
|
|
124
|
+
.default(false)
|
|
125
|
+
.describe(`
|
|
126
|
+
Whether to strip document metadata (title, author, keywords, etc.) from the PDF. This can provide a small reduction in file size and may be useful for privacy.
|
|
127
|
+
`),
|
|
128
|
+
linearize: z
|
|
129
|
+
.boolean()
|
|
130
|
+
.default(true)
|
|
131
|
+
.describe(`
|
|
132
|
+
Whether to linearize (optimize for Fast Web View) the output PDF. Linearized PDFs can begin displaying in a browser before they are fully downloaded, improving the user experience for web delivery.
|
|
133
|
+
`),
|
|
134
|
+
compatibility: z
|
|
135
|
+
.enum(['1.4', '1.5', '1.6', '1.7', '2.0'])
|
|
136
|
+
.default('1.7')
|
|
137
|
+
.describe(`
|
|
138
|
+
The PDF version compatibility level. Lower versions have broader compatibility but fewer features. Higher versions support more advanced features but may not open in older PDF readers.
|
|
139
|
+
|
|
140
|
+
- \`1.4\` - Acrobat 5 compatibility, most widely supported
|
|
141
|
+
- \`1.5\` - Acrobat 6 compatibility
|
|
142
|
+
- \`1.6\` - Acrobat 7 compatibility
|
|
143
|
+
- \`1.7\` - Acrobat 8+ compatibility (default)
|
|
144
|
+
- \`2.0\` - PDF 2.0 standard
|
|
145
|
+
`),
|
|
146
|
+
})
|
|
147
|
+
.strict()
|
|
148
|
+
|
|
149
|
+
export const robotDocumentOptimizeInstructionsWithHiddenFieldsSchema =
|
|
150
|
+
robotDocumentOptimizeInstructionsSchema.extend({
|
|
151
|
+
result: z
|
|
152
|
+
.union([z.literal('debug'), robotDocumentOptimizeInstructionsSchema.shape.result])
|
|
153
|
+
.optional(),
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
export type RobotDocumentOptimizeInstructions = z.infer<
|
|
157
|
+
typeof robotDocumentOptimizeInstructionsSchema
|
|
158
|
+
>
|
|
159
|
+
export type RobotDocumentOptimizeInstructionsWithHiddenFields = z.infer<
|
|
160
|
+
typeof robotDocumentOptimizeInstructionsWithHiddenFieldsSchema
|
|
161
|
+
>
|
|
162
|
+
|
|
163
|
+
export const interpolatableRobotDocumentOptimizeInstructionsSchema = interpolateRobot(
|
|
164
|
+
robotDocumentOptimizeInstructionsSchema,
|
|
165
|
+
)
|
|
166
|
+
export type InterpolatableRobotDocumentOptimizeInstructions =
|
|
167
|
+
InterpolatableRobotDocumentOptimizeInstructionsInput
|
|
168
|
+
|
|
169
|
+
export type InterpolatableRobotDocumentOptimizeInstructionsInput = z.input<
|
|
170
|
+
typeof interpolatableRobotDocumentOptimizeInstructionsSchema
|
|
171
|
+
>
|
|
172
|
+
|
|
173
|
+
export const interpolatableRobotDocumentOptimizeInstructionsWithHiddenFieldsSchema =
|
|
174
|
+
interpolateRobot(robotDocumentOptimizeInstructionsWithHiddenFieldsSchema)
|
|
175
|
+
export type InterpolatableRobotDocumentOptimizeInstructionsWithHiddenFields = z.infer<
|
|
176
|
+
typeof interpolatableRobotDocumentOptimizeInstructionsWithHiddenFieldsSchema
|
|
177
|
+
>
|
|
178
|
+
export type InterpolatableRobotDocumentOptimizeInstructionsWithHiddenFieldsInput = z.input<
|
|
179
|
+
typeof interpolatableRobotDocumentOptimizeInstructionsWithHiddenFieldsSchema
|
|
180
|
+
>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
declare module 'json-to-ast' {
|
|
2
|
+
export interface JsonToAstLocation {
|
|
3
|
+
start: { line: number; column: number }
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface ObjectPropertyNode {
|
|
7
|
+
key: { value: string; loc?: JsonToAstLocation }
|
|
8
|
+
value: ValueNode
|
|
9
|
+
loc?: JsonToAstLocation
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface LiteralNode {
|
|
13
|
+
type: 'Literal'
|
|
14
|
+
value: unknown
|
|
15
|
+
loc?: JsonToAstLocation
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ArrayNode {
|
|
19
|
+
type: 'Array'
|
|
20
|
+
children: ValueNode[]
|
|
21
|
+
loc?: JsonToAstLocation
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ObjectNode {
|
|
25
|
+
type: 'Object'
|
|
26
|
+
children: ObjectPropertyNode[]
|
|
27
|
+
loc?: JsonToAstLocation
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type ValueNode = LiteralNode | ArrayNode | ObjectNode
|
|
31
|
+
|
|
32
|
+
const parse: (source: string, options?: { loc?: boolean }) => ValueNode
|
|
33
|
+
export default parse
|
|
34
|
+
}
|
|
@@ -13,15 +13,19 @@ import got from 'got'
|
|
|
13
13
|
import PQueue from 'p-queue'
|
|
14
14
|
import * as t from 'typanion'
|
|
15
15
|
import { z } from 'zod'
|
|
16
|
+
import { formatLintIssue } from '../../alphalib/assembly-linter.lang.en.ts'
|
|
16
17
|
import { tryCatch } from '../../alphalib/tryCatch.ts'
|
|
17
18
|
import type { Steps, StepsInput } from '../../alphalib/types/template.ts'
|
|
18
19
|
import { stepsSchema } from '../../alphalib/types/template.ts'
|
|
19
20
|
import type { CreateAssemblyParams, ReplayAssemblyParams } from '../../apiTypes.ts'
|
|
21
|
+
import type { LintFatalLevel } from '../../lintAssemblyInstructions.ts'
|
|
22
|
+
import { lintAssemblyInstructions } from '../../lintAssemblyInstructions.ts'
|
|
20
23
|
import type { CreateAssemblyOptions, Transloadit } from '../../Transloadit.ts'
|
|
21
|
-
import {
|
|
24
|
+
import { lintingExamples } from '../docs/assemblyLintingExamples.ts'
|
|
25
|
+
import { createReadStream, formatAPIError, readCliInput, streamToBuffer } from '../helpers.ts'
|
|
22
26
|
import type { IOutputCtl } from '../OutputCtl.ts'
|
|
23
27
|
import { ensureError, isErrnoException } from '../types.ts'
|
|
24
|
-
import { AuthenticatedCommand } from './BaseCommand.ts'
|
|
28
|
+
import { AuthenticatedCommand, UnauthenticatedCommand } from './BaseCommand.ts'
|
|
25
29
|
|
|
26
30
|
// --- From assemblies.ts: Schemas and interfaces ---
|
|
27
31
|
export interface AssemblyListOptions {
|
|
@@ -48,6 +52,15 @@ export interface AssemblyReplayOptions {
|
|
|
48
52
|
assemblies: string[]
|
|
49
53
|
}
|
|
50
54
|
|
|
55
|
+
export interface AssemblyLintOptions {
|
|
56
|
+
steps?: string
|
|
57
|
+
template?: string
|
|
58
|
+
fatal?: LintFatalLevel
|
|
59
|
+
fix?: boolean
|
|
60
|
+
providedInput?: string
|
|
61
|
+
json?: boolean
|
|
62
|
+
}
|
|
63
|
+
|
|
51
64
|
const AssemblySchema = z.object({
|
|
52
65
|
id: z.string(),
|
|
53
66
|
})
|
|
@@ -163,6 +176,97 @@ export async function replay(
|
|
|
163
176
|
}
|
|
164
177
|
}
|
|
165
178
|
|
|
179
|
+
export async function lint(
|
|
180
|
+
output: IOutputCtl,
|
|
181
|
+
client: Transloadit | null,
|
|
182
|
+
{ steps, template, fatal, fix, providedInput, json }: AssemblyLintOptions,
|
|
183
|
+
): Promise<number> {
|
|
184
|
+
let content: string | null
|
|
185
|
+
let isStdin: boolean
|
|
186
|
+
let inputPath: string | undefined
|
|
187
|
+
try {
|
|
188
|
+
;({
|
|
189
|
+
content,
|
|
190
|
+
isStdin,
|
|
191
|
+
path: inputPath,
|
|
192
|
+
} = await readCliInput({
|
|
193
|
+
inputPath: steps,
|
|
194
|
+
providedInput,
|
|
195
|
+
allowStdinWhenNoPath: true,
|
|
196
|
+
}))
|
|
197
|
+
} catch (error) {
|
|
198
|
+
output.error(ensureError(error).message)
|
|
199
|
+
return 1
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (content == null && template == null) {
|
|
203
|
+
output.error('assemblies lint requires --steps or stdin input unless --template is provided')
|
|
204
|
+
return 1
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (fix && content == null && template != null) {
|
|
208
|
+
output.error('assemblies lint --fix requires local instructions (stdin or --steps)')
|
|
209
|
+
return 1
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
let result: Awaited<ReturnType<typeof lintAssemblyInstructions>>
|
|
213
|
+
try {
|
|
214
|
+
if (template != null) {
|
|
215
|
+
if (!client) {
|
|
216
|
+
output.error('Missing client for template lookup')
|
|
217
|
+
return 1
|
|
218
|
+
}
|
|
219
|
+
result = await client.lintAssemblyInstructions({
|
|
220
|
+
assemblyInstructions: content ?? undefined,
|
|
221
|
+
templateId: template,
|
|
222
|
+
fatal,
|
|
223
|
+
fix,
|
|
224
|
+
})
|
|
225
|
+
} else {
|
|
226
|
+
result = await lintAssemblyInstructions({
|
|
227
|
+
assemblyInstructions: content ?? undefined,
|
|
228
|
+
fatal,
|
|
229
|
+
fix,
|
|
230
|
+
})
|
|
231
|
+
}
|
|
232
|
+
} catch (error) {
|
|
233
|
+
output.error(ensureError(error).message)
|
|
234
|
+
return 1
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const issues = result.issues
|
|
238
|
+
|
|
239
|
+
if (fix && isStdin) {
|
|
240
|
+
if (result.fixedInstructions == null) {
|
|
241
|
+
output.error('No fixed output available.')
|
|
242
|
+
return 1
|
|
243
|
+
}
|
|
244
|
+
process.stdout.write(`${result.fixedInstructions}\n`)
|
|
245
|
+
for (const issue of issues) {
|
|
246
|
+
const line = formatLintIssue(issue)
|
|
247
|
+
if (issue.type === 'warning') output.warn(line)
|
|
248
|
+
else output.error(line)
|
|
249
|
+
}
|
|
250
|
+
return result.success ? 0 : 1
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (fix && inputPath && result.fixedInstructions != null) {
|
|
254
|
+
await fsp.writeFile(inputPath, result.fixedInstructions)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (json) {
|
|
258
|
+
output.print({ ...result, issues }, result)
|
|
259
|
+
} else if (issues.length === 0) {
|
|
260
|
+
output.print('No issues found', result)
|
|
261
|
+
} else {
|
|
262
|
+
for (const issue of issues) {
|
|
263
|
+
output.print(formatLintIssue(issue), issue)
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return result.success ? 0 : 1
|
|
268
|
+
}
|
|
269
|
+
|
|
166
270
|
// --- From assemblies-create.ts: Helper classes and functions ---
|
|
167
271
|
interface NodeWatcher {
|
|
168
272
|
on(event: 'error', listener: (err: Error) => void): void
|
|
@@ -1373,3 +1477,58 @@ export class AssembliesReplayCommand extends AuthenticatedCommand {
|
|
|
1373
1477
|
return undefined
|
|
1374
1478
|
}
|
|
1375
1479
|
}
|
|
1480
|
+
|
|
1481
|
+
export class AssembliesLintCommand extends UnauthenticatedCommand {
|
|
1482
|
+
static override paths = [
|
|
1483
|
+
['assemblies', 'lint'],
|
|
1484
|
+
['assembly', 'lint'],
|
|
1485
|
+
['a', 'lint'],
|
|
1486
|
+
]
|
|
1487
|
+
|
|
1488
|
+
static override usage = Command.Usage({
|
|
1489
|
+
category: 'Assemblies',
|
|
1490
|
+
description: 'Lint Assembly Instructions',
|
|
1491
|
+
details: `
|
|
1492
|
+
Lint Assembly Instructions locally using Transloadit's linter.
|
|
1493
|
+
Provide instructions via --steps or stdin (steps-only JSON is accepted).
|
|
1494
|
+
Optionally pass --template to
|
|
1495
|
+
merge template content with steps before linting (same merge behavior as the API).
|
|
1496
|
+
`,
|
|
1497
|
+
examples: lintingExamples,
|
|
1498
|
+
})
|
|
1499
|
+
|
|
1500
|
+
steps = Option.String('--steps,-s', {
|
|
1501
|
+
description: 'JSON file with Assembly Instructions (use "-" for stdin)',
|
|
1502
|
+
})
|
|
1503
|
+
|
|
1504
|
+
template = Option.String('--template,-t', {
|
|
1505
|
+
description:
|
|
1506
|
+
'Template ID to merge before linting. If the template forbids step overrides, linting will fail when steps are provided.',
|
|
1507
|
+
})
|
|
1508
|
+
|
|
1509
|
+
fatal = Option.String('--fatal', {
|
|
1510
|
+
description: 'Treat issues at this level as fatal (error or warning)',
|
|
1511
|
+
validator: t.isEnum(['error', 'warning']),
|
|
1512
|
+
})
|
|
1513
|
+
|
|
1514
|
+
fix = Option.Boolean('--fix', false, {
|
|
1515
|
+
description:
|
|
1516
|
+
'Apply auto-fixes. For files, overwrites in place. For stdin, writes fixed JSON to stdout.',
|
|
1517
|
+
})
|
|
1518
|
+
|
|
1519
|
+
protected async run(): Promise<number | undefined> {
|
|
1520
|
+
let client: Transloadit | null = null
|
|
1521
|
+
if (this.template) {
|
|
1522
|
+
if (!this.setupClient()) return 1
|
|
1523
|
+
client = this.client
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
return await lint(this.output, client, {
|
|
1527
|
+
steps: this.steps,
|
|
1528
|
+
template: this.template,
|
|
1529
|
+
fatal: this.fatal as LintFatalLevel | undefined,
|
|
1530
|
+
fix: this.fix,
|
|
1531
|
+
json: this.json,
|
|
1532
|
+
})
|
|
1533
|
+
}
|
|
1534
|
+
}
|
package/src/cli/commands/auth.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from '../../alphalib/types/template.ts'
|
|
9
9
|
import type { OptionalAuthParams } from '../../apiTypes.ts'
|
|
10
10
|
import { Transloadit } from '../../Transloadit.ts'
|
|
11
|
-
import { getEnvCredentials } from '../helpers.ts'
|
|
11
|
+
import { getEnvCredentials, readCliInput } from '../helpers.ts'
|
|
12
12
|
import { UnauthenticatedCommand } from './BaseCommand.ts'
|
|
13
13
|
|
|
14
14
|
type UrlParamPrimitive = string | number | boolean
|
|
@@ -68,19 +68,6 @@ function normalizeUrlParams(params?: Record<string, unknown>): NormalizedUrlPara
|
|
|
68
68
|
return normalized
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
async function readStdin(): Promise<string> {
|
|
72
|
-
if (process.stdin.isTTY) return ''
|
|
73
|
-
|
|
74
|
-
process.stdin.setEncoding('utf8')
|
|
75
|
-
let data = ''
|
|
76
|
-
|
|
77
|
-
for await (const chunk of process.stdin) {
|
|
78
|
-
data += chunk
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return data
|
|
82
|
-
}
|
|
83
|
-
|
|
84
71
|
const getCredentials = getEnvCredentials
|
|
85
72
|
|
|
86
73
|
// Result type for signature operations
|
|
@@ -217,8 +204,12 @@ export async function runSig(options: RunSigOptions = {}): Promise<void> {
|
|
|
217
204
|
return
|
|
218
205
|
}
|
|
219
206
|
|
|
220
|
-
const
|
|
221
|
-
|
|
207
|
+
const { content } = await readCliInput({
|
|
208
|
+
providedInput: options.providedInput,
|
|
209
|
+
allowStdinWhenNoPath: true,
|
|
210
|
+
})
|
|
211
|
+
const rawInput = (content ?? '').trim()
|
|
212
|
+
const result = generateSignature(rawInput, credentials, options.algorithm)
|
|
222
213
|
|
|
223
214
|
if (result.ok) {
|
|
224
215
|
process.stdout.write(`${result.output}\n`)
|
|
@@ -238,8 +229,12 @@ export async function runSmartSig(options: RunSmartSigOptions = {}): Promise<voi
|
|
|
238
229
|
return
|
|
239
230
|
}
|
|
240
231
|
|
|
241
|
-
const
|
|
242
|
-
|
|
232
|
+
const { content } = await readCliInput({
|
|
233
|
+
providedInput: options.providedInput,
|
|
234
|
+
allowStdinWhenNoPath: true,
|
|
235
|
+
})
|
|
236
|
+
const rawInput = (content ?? '').trim()
|
|
237
|
+
const result = generateSmartCdnUrl(rawInput, credentials)
|
|
243
238
|
|
|
244
239
|
if (result.ok) {
|
|
245
240
|
process.stdout.write(`${result.output}\n`)
|
|
@@ -287,8 +282,9 @@ export class SignatureCommand extends UnauthenticatedCommand {
|
|
|
287
282
|
return 1
|
|
288
283
|
}
|
|
289
284
|
|
|
290
|
-
const
|
|
291
|
-
const
|
|
285
|
+
const { content } = await readCliInput({ allowStdinWhenNoPath: true })
|
|
286
|
+
const rawInput = (content ?? '').trim()
|
|
287
|
+
const result = generateSignature(rawInput, credentials, this.algorithm)
|
|
292
288
|
|
|
293
289
|
if (result.ok) {
|
|
294
290
|
process.stdout.write(`${result.output}\n`)
|
|
@@ -340,8 +336,9 @@ export class SmartCdnSignatureCommand extends UnauthenticatedCommand {
|
|
|
340
336
|
return 1
|
|
341
337
|
}
|
|
342
338
|
|
|
343
|
-
const
|
|
344
|
-
const
|
|
339
|
+
const { content } = await readCliInput({ allowStdinWhenNoPath: true })
|
|
340
|
+
const rawInput = (content ?? '').trim()
|
|
341
|
+
const result = generateSmartCdnUrl(rawInput, credentials)
|
|
345
342
|
|
|
346
343
|
if (result.ok) {
|
|
347
344
|
process.stdout.write(`${result.output}\n`)
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
AssembliesCreateCommand,
|
|
7
7
|
AssembliesDeleteCommand,
|
|
8
8
|
AssembliesGetCommand,
|
|
9
|
+
AssembliesLintCommand,
|
|
9
10
|
AssembliesListCommand,
|
|
10
11
|
AssembliesReplayCommand,
|
|
11
12
|
} from './assemblies.ts'
|
|
@@ -46,6 +47,7 @@ export function createCli(): Cli {
|
|
|
46
47
|
cli.register(AssembliesGetCommand)
|
|
47
48
|
cli.register(AssembliesDeleteCommand)
|
|
48
49
|
cli.register(AssembliesReplayCommand)
|
|
50
|
+
cli.register(AssembliesLintCommand)
|
|
49
51
|
|
|
50
52
|
// Templates commands
|
|
51
53
|
cli.register(TemplatesCreateCommand)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const lintingExamples: Array<[string, string]> = [
|
|
2
|
+
['Lint a steps file', 'transloadit assemblies lint --steps steps.json'],
|
|
3
|
+
['Lint from stdin', 'cat steps.json | transloadit assemblies lint --steps -'],
|
|
4
|
+
[
|
|
5
|
+
'Lint with template merge',
|
|
6
|
+
'transloadit assemblies lint --template TEMPLATE_ID --steps steps.json',
|
|
7
|
+
],
|
|
8
|
+
['Auto-fix in place', 'transloadit assemblies lint --steps steps.json --fix'],
|
|
9
|
+
]
|