@giveitsmaller/sdk 0.18.0 → 0.19.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 +1 -1
- package/dist/ergonomic/image_output_routes.d.ts +6 -5
- package/dist/ergonomic/image_output_routes.js +29 -21
- package/dist/ergonomic/option_types.d.ts +51 -10
- package/dist/ergonomic/option_types.js +6 -5
- package/dist/ergonomic/option_validation.d.ts +2 -2
- package/dist/ergonomic/option_validation.js +2 -2
- package/dist/ergonomic/preset_resolver.d.ts +1 -1
- package/dist/ergonomic/preset_resolver.js +6 -7
- package/dist/ergonomic/presets/document_epub_compress.d.ts +0 -2
- package/dist/ergonomic/presets/document_epub_compress.js +2 -7
- package/dist/ergonomic/presets/document_odf_compress.d.ts +0 -2
- package/dist/ergonomic/presets/document_odf_compress.js +2 -7
- package/dist/ergonomic/presets/document_office_compress.d.ts +0 -2
- package/dist/ergonomic/presets/document_office_compress.js +2 -7
- package/dist/file-first.d.ts +42 -5
- package/dist/file-first.js +48 -12
- package/dist/generated/sdk_spec/enums.d.ts +4 -2
- package/dist/generated/sdk_spec/enums.js +11 -5
- package/dist/generated/sdk_spec/presets.js +3 -12
- package/dist/generated/sdk_spec/version.d.ts +3 -3
- package/dist/generated/sdk_spec/version.js +3 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -67,7 +67,7 @@ Docs are published in the [giveitsmaller-sdks](https://github.com/AntonioCS/give
|
|
|
67
67
|
- **Webhooks** — [`docs/typescript/webhook.md`](https://github.com/AntonioCS/giveitsmaller-sdks/blob/main/docs/typescript/webhook.md)
|
|
68
68
|
- **Errors & retry guidance** — [`docs/typescript/errors.md`](https://github.com/AntonioCS/giveitsmaller-sdks/blob/main/docs/typescript/errors.md)
|
|
69
69
|
- **Troubleshooting** — [`docs/typescript/troubleshooting.md`](https://github.com/AntonioCS/giveitsmaller-sdks/blob/main/docs/typescript/troubleshooting.md)
|
|
70
|
-
- **Examples** — compress, thumbnail, convert, merge, archive — [`docs/typescript/examples/`](https://github.com/AntonioCS/giveitsmaller-sdks/tree/main/docs/typescript/examples)
|
|
70
|
+
- **Examples** — compress, thumbnail, convert, merge, archive, watermark, output — [`docs/typescript/examples/`](https://github.com/AntonioCS/giveitsmaller-sdks/tree/main/docs/typescript/examples)
|
|
71
71
|
|
|
72
72
|
## Contributing: the committed `dist/`
|
|
73
73
|
|
|
@@ -12,11 +12,12 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Each route cell lists the options the worker HONORS (live) and PLANS (advertised,
|
|
14
14
|
* not yet honored — gated unavailable). Resize (`width`/`height`/`fit`) is
|
|
15
|
-
* **INPUT-
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* capability from `same_format
|
|
19
|
-
* `
|
|
15
|
+
* **INPUT-gated**: since v2.103.0 convert is the resize engine, so the projection
|
|
16
|
+
* lists resize on every `format_change` cell too — but resizability is keyed to the
|
|
17
|
+
* INPUT (raster only — `svg` is vector and carries no resize). The lowering reads
|
|
18
|
+
* resize capability from `same_format[input]` on BOTH routes, so a `png → webp +
|
|
19
|
+
* resize` request resizes (png is raster) while an `svg → png + resize` request
|
|
20
|
+
* does NOT (svg's same_format cell has no resize keys).
|
|
20
21
|
*
|
|
21
22
|
* This hand table MIRRORS the generated projection and is PINNED to it by
|
|
22
23
|
* `output-route-conformance.test.ts` (the watermark-capability-gate precedent) —
|
|
@@ -12,11 +12,12 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Each route cell lists the options the worker HONORS (live) and PLANS (advertised,
|
|
14
14
|
* not yet honored — gated unavailable). Resize (`width`/`height`/`fit`) is
|
|
15
|
-
* **INPUT-
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* capability from `same_format
|
|
19
|
-
* `
|
|
15
|
+
* **INPUT-gated**: since v2.103.0 convert is the resize engine, so the projection
|
|
16
|
+
* lists resize on every `format_change` cell too — but resizability is keyed to the
|
|
17
|
+
* INPUT (raster only — `svg` is vector and carries no resize). The lowering reads
|
|
18
|
+
* resize capability from `same_format[input]` on BOTH routes, so a `png → webp +
|
|
19
|
+
* resize` request resizes (png is raster) while an `svg → png + resize` request
|
|
20
|
+
* does NOT (svg's same_format cell has no resize keys).
|
|
20
21
|
*
|
|
21
22
|
* This hand table MIRRORS the generated projection and is PINNED to it by
|
|
22
23
|
* `output-route-conformance.test.ts` (the watermark-capability-gate precedent) —
|
|
@@ -28,6 +29,8 @@
|
|
|
28
29
|
import { compressMetadata } from '@giveitsmaller/contracts/operations';
|
|
29
30
|
/** The resize option keys — input-keyed, raster-only (see module doc). */
|
|
30
31
|
export const RESIZE_KEYS = ['width', 'height', 'fit'];
|
|
32
|
+
/** Set form of {@link RESIZE_KEYS} for `string`-keyed membership tests. */
|
|
33
|
+
const RESIZE_KEY_SET = new Set(RESIZE_KEYS);
|
|
31
34
|
/** Image area cap shared by every resizable route (projection `max_output_pixels`). */
|
|
32
35
|
export const MAX_OUTPUT_PIXELS = 16_000_000;
|
|
33
36
|
/**
|
|
@@ -61,21 +64,21 @@ const EXT_TOKEN = {
|
|
|
61
64
|
*/
|
|
62
65
|
export const IMAGE_OUTPUT_ROUTES = {
|
|
63
66
|
same_format: {
|
|
64
|
-
avif: { honored: ['avif_speed', 'fit', 'height', 'metadata', 'output_format', 'quality', 'width'], planned: [] },
|
|
65
|
-
gif: { honored: ['fit', 'height', 'metadata', 'output_format', 'quality', 'width'], planned: [] },
|
|
66
|
-
jpeg: { honored: ['fit', 'height', 'lossless', 'metadata', 'output_format', 'progressive', 'quality', 'width'], planned: [] },
|
|
67
|
-
png: { honored: ['fit', 'height', 'metadata', 'optimization_level', 'output_format', 'quality', 'width'], planned: [
|
|
68
|
-
svg: { honored: ['metadata', 'output_format'
|
|
69
|
-
tiff: { honored: ['fit', 'height', 'metadata', 'output_format', 'quality', 'width'], planned: [] },
|
|
70
|
-
webp: { honored: ['fit', 'height', 'lossless', 'metadata', 'output_format', 'quality', 'width'], planned: [] },
|
|
67
|
+
avif: { honored: ['auto_orient', 'avif_speed', 'color_profile', 'encoding_mode', 'fit', 'height', 'metadata', 'output_format', 'quality', 'quality_preset', 'target_size_bytes', 'width'], planned: [] },
|
|
68
|
+
gif: { honored: ['auto_orient', 'color_profile', 'fit', 'height', 'metadata', 'output_format', 'quality', 'width'], planned: [] },
|
|
69
|
+
jpeg: { honored: ['auto_orient', 'chroma_subsampling', 'color_profile', 'encoding_mode', 'fit', 'height', 'lossless', 'metadata', 'output_format', 'progressive', 'quality', 'quality_preset', 'target_size_bytes', 'width'], planned: [] },
|
|
70
|
+
png: { honored: ['auto_orient', 'color_profile', 'fit', 'height', 'metadata', 'optimization_level', 'output_format', 'quality', 'width'], planned: [] },
|
|
71
|
+
svg: { honored: ['metadata', 'output_format'], planned: [] },
|
|
72
|
+
tiff: { honored: ['auto_orient', 'color_profile', 'fit', 'height', 'metadata', 'output_format', 'quality', 'width'], planned: [] },
|
|
73
|
+
webp: { honored: ['auto_orient', 'color_profile', 'encoding_mode', 'fit', 'height', 'lossless', 'metadata', 'output_format', 'quality', 'quality_preset', 'target_size_bytes', 'width'], planned: [] },
|
|
71
74
|
},
|
|
72
75
|
format_change: {
|
|
73
|
-
avif: { honored: ['output_format', 'quality'], planned: [] },
|
|
74
|
-
gif: { honored: ['output_format'], planned: [] },
|
|
75
|
-
jpeg: { honored: ['background', 'output_format', 'quality'], planned: [] },
|
|
76
|
-
png: { honored: ['output_format'], planned: [] },
|
|
77
|
-
tiff: { honored: ['output_format'], planned: [] },
|
|
78
|
-
webp: { honored: ['output_format', 'quality'], planned: [] },
|
|
76
|
+
avif: { honored: ['auto_orient', 'color_profile', 'fit', 'height', 'output_format', 'quality', 'width'], planned: ['metadata'] },
|
|
77
|
+
gif: { honored: ['auto_orient', 'color_profile', 'fit', 'height', 'output_format', 'width'], planned: ['metadata'] },
|
|
78
|
+
jpeg: { honored: ['auto_orient', 'background', 'color_profile', 'fit', 'height', 'output_format', 'quality', 'width'], planned: ['metadata'] },
|
|
79
|
+
png: { honored: ['auto_orient', 'color_profile', 'fit', 'height', 'output_format', 'width'], planned: ['metadata'] },
|
|
80
|
+
tiff: { honored: ['auto_orient', 'color_profile', 'fit', 'height', 'output_format', 'width'], planned: ['metadata'] },
|
|
81
|
+
webp: { honored: ['auto_orient', 'color_profile', 'fit', 'height', 'output_format', 'quality', 'width'], planned: ['metadata'] },
|
|
79
82
|
},
|
|
80
83
|
};
|
|
81
84
|
/** The bare format token for a MIME type, or undefined if not a known image MIME. */
|
|
@@ -114,8 +117,13 @@ export function resolveOutputRoute(inputToken, outputFormat) {
|
|
|
114
117
|
const cell = IMAGE_OUTPUT_ROUTES.format_change[outToken];
|
|
115
118
|
if (cell === undefined)
|
|
116
119
|
return undefined;
|
|
117
|
-
//
|
|
118
|
-
//
|
|
120
|
+
// Resize is INPUT-gated. Since v2.103.0 convert is the resize engine, so the
|
|
121
|
+
// projection lists width/height/fit on EVERY format_change cell — but an SVG
|
|
122
|
+
// INPUT cannot be raster-resized (the convert worker rejects it). So strip the
|
|
123
|
+
// cell's resize keys and re-add only those the INPUT's same_format cell honors:
|
|
124
|
+
// raster inputs carry them, svg does not. The transcoder options (output_format/
|
|
125
|
+
// quality/background) ride the cell directly.
|
|
126
|
+
const transcoderHonored = cell.honored.filter((k) => !RESIZE_KEY_SET.has(k));
|
|
119
127
|
const inCell = IMAGE_OUTPUT_ROUTES.same_format[inputToken];
|
|
120
128
|
const resize = inCell ? RESIZE_KEYS.filter((k) => inCell.honored.includes(k)) : [];
|
|
121
129
|
return {
|
|
@@ -123,7 +131,7 @@ export function resolveOutputRoute(inputToken, outputFormat) {
|
|
|
123
131
|
sourceOp: 'convert',
|
|
124
132
|
outputFormatWire: outToken,
|
|
125
133
|
inputToken,
|
|
126
|
-
honored: new Set([...
|
|
134
|
+
honored: new Set([...transcoderHonored, ...resize]),
|
|
127
135
|
planned: new Set(cell.planned),
|
|
128
136
|
};
|
|
129
137
|
}
|
|
@@ -29,8 +29,18 @@ export interface ConvertOptions {
|
|
|
29
29
|
trim_end?: number;
|
|
30
30
|
/** Output frame rate for video → GIF. */
|
|
31
31
|
fps?: number;
|
|
32
|
-
/**
|
|
32
|
+
/** Resize width in px. Image convert: resize-on-convert (1-16384, width*height ≤ 16MP, v2.103.0). Video → GIF: downscale cap. */
|
|
33
33
|
width?: number;
|
|
34
|
+
/** Resize height in px for image convert (1-16384, v2.103.0). Omit for width-only / aspect-preserving resize. Not honored for SVG input. */
|
|
35
|
+
height?: number;
|
|
36
|
+
/** Resize mode for image convert (applies when width or height is set, v2.103.0). `max` never upscales. */
|
|
37
|
+
fit?: 'max' | 'crop' | 'scale';
|
|
38
|
+
/** Metadata policy for image convert (`strip` removes EXIF/IPTC/XMP, `keep` preserves). PLANNED on convert.image (v2.106.0). */
|
|
39
|
+
metadata?: 'strip' | 'keep';
|
|
40
|
+
/** ICC colour-profile handling for image convert (`keep`/`srgb`/`strip`). PLANNED on convert.image (v2.112.0). */
|
|
41
|
+
color_profile?: 'keep' | 'srgb' | 'strip';
|
|
42
|
+
/** Auto-rotate per EXIF orientation for image convert. STABLE since v2.120.0. */
|
|
43
|
+
auto_orient?: boolean;
|
|
34
44
|
/** GIF palette size (2-256). */
|
|
35
45
|
max_colors?: number;
|
|
36
46
|
/** GIF loop count (0 infinite, N>0 N times, -1 once). */
|
|
@@ -55,6 +65,8 @@ export interface ThumbnailOptions {
|
|
|
55
65
|
format?: 'jpg' | 'png' | 'webp';
|
|
56
66
|
/** Output quality for lossy thumbnail formats (image input). */
|
|
57
67
|
quality?: number;
|
|
68
|
+
/** Background fill colour (hex) for transparency flattened to JPG output (v2.118.0). */
|
|
69
|
+
background?: string;
|
|
58
70
|
/** Frame timestamp for video input (e.g. '00:00:01'). */
|
|
59
71
|
timestamp?: string;
|
|
60
72
|
/** Document source: a printed page or the cover. */
|
|
@@ -98,8 +110,27 @@ export interface WatermarkOptions {
|
|
|
98
110
|
}
|
|
99
111
|
/** Resize mode (contract `fit` enum, v2.97.0). */
|
|
100
112
|
export type OutputFit = 'max' | 'crop' | 'scale';
|
|
101
|
-
/**
|
|
102
|
-
|
|
113
|
+
/**
|
|
114
|
+
* Metadata policy (contract `metadata` enum). `strip` (default) removes all
|
|
115
|
+
* EXIF/IPTC/XMP; `keep` preserves them. Honored on same_format; PLANNED on
|
|
116
|
+
* format_change (v2.106.0). Renamed in contracts v2.107.0 — the legacy `all`
|
|
117
|
+
* token is now a DEPRECATED alias of `strip` (still accepted on the wire, emits
|
|
118
|
+
* a Deprecation header); use `strip`.
|
|
119
|
+
*/
|
|
120
|
+
export type OutputMetadata = 'strip' | 'keep';
|
|
121
|
+
/**
|
|
122
|
+
* Compression mode on the optimiser (same_format) route (contract `encoding_mode`
|
|
123
|
+
* enum). `quality` (default) drives the encode by the quality slider; `target_size`
|
|
124
|
+
* targets a byte budget via the worker's encode-measure loop — STABLE since
|
|
125
|
+
* contracts v2.108.0 (jpeg/webp/avif).
|
|
126
|
+
*/
|
|
127
|
+
export type OutputEncodingMode = 'quality' | 'target_size';
|
|
128
|
+
/** Chroma subsampling for JPEG output (contract `chroma_subsampling` enum, v2.110.0). `420` smallest → `444` highest fidelity. Honored: same_format jpeg only. */
|
|
129
|
+
export type OutputChromaSubsampling = '420' | '422' | '444';
|
|
130
|
+
/** ICC colour-profile handling (contract `color_profile` enum, v2.112.0). `keep` preserves the embedded profile; `srgb` converts to sRGB; `strip` removes it. Route/value availability is gated by the output lowering. */
|
|
131
|
+
export type OutputColorProfile = 'keep' | 'srgb' | 'strip';
|
|
132
|
+
/** Named quality preset (contract `quality_preset` enum, v2.148.0) — an alternative to the numeric `quality` slider. `best` highest fidelity → `low` smallest. Honored: same_format avif/jpeg/webp. */
|
|
133
|
+
export type OutputQualityPreset = 'best' | 'good' | 'fair' | 'low';
|
|
103
134
|
/**
|
|
104
135
|
* Options for the file-first `output()` image transform. The KEY SET is the
|
|
105
136
|
* UNION of every image route's honored + planned option keys (image-output-routes
|
|
@@ -110,8 +141,16 @@ export type OutputMetadata = 'all' | 'keep';
|
|
|
110
141
|
* `fit`) is honored on raster routes; `height` is optional (width-only resize).
|
|
111
142
|
*/
|
|
112
143
|
export interface OutputOptions {
|
|
113
|
-
/** Output quality
|
|
144
|
+
/** Output quality (1-100). Honored on same-format avif/jpeg/png/webp and lossy format-change routes. */
|
|
114
145
|
quality?: number;
|
|
146
|
+
/** Named quality preset (`best`/`good`/`fair`/`low`) — an alternative to the numeric `quality` slider (v2.148.0). Honored: same_format avif/jpeg/webp. */
|
|
147
|
+
quality_preset?: OutputQualityPreset;
|
|
148
|
+
/** Compression mode (same_format avif/jpeg/webp). `quality` (default) or `target_size` — STABLE since v2.108.0. */
|
|
149
|
+
encoding_mode?: OutputEncodingMode;
|
|
150
|
+
/** Target output size in bytes (≥1024) for `encoding_mode: 'target_size'`. STABLE since v2.108.0. Honored: same_format avif/jpeg/webp. */
|
|
151
|
+
target_size_bytes?: number;
|
|
152
|
+
/** Chroma subsampling for JPEG output. Honored: same_format jpeg only (v2.110.0). */
|
|
153
|
+
chroma_subsampling?: OutputChromaSubsampling;
|
|
115
154
|
/** Resize target width in px (1-16384; width*height <= 16MP). */
|
|
116
155
|
width?: number;
|
|
117
156
|
/** Resize target height in px (optional — width-only resize preserves aspect). */
|
|
@@ -126,12 +165,14 @@ export interface OutputOptions {
|
|
|
126
165
|
optimization_level?: number;
|
|
127
166
|
/** AVIF encode speed. Honored: same_format avif only. */
|
|
128
167
|
avif_speed?: number;
|
|
129
|
-
/** Metadata policy
|
|
168
|
+
/** Metadata policy (`strip` default / `keep`). Honored: same_format; PLANNED on format_change (v2.106.0). */
|
|
130
169
|
metadata?: OutputMetadata;
|
|
170
|
+
/** ICC colour-profile handling (`keep`/`srgb`/`strip`). Availability depends on route and value. */
|
|
171
|
+
color_profile?: OutputColorProfile;
|
|
172
|
+
/** Auto-rotate per EXIF orientation. STABLE since v2.120.0 (both routes). */
|
|
173
|
+
auto_orient?: boolean;
|
|
131
174
|
/** JPEG/WebP lossless. Honored: same_format jpeg/webp (stable since v2.101.0). */
|
|
132
175
|
lossless?: boolean;
|
|
133
|
-
/** Lossy PNG quantization. PLANNED (gated unavailable; licence-gated). */
|
|
134
|
-
lossy?: boolean;
|
|
135
176
|
}
|
|
136
177
|
/**
|
|
137
178
|
* The user-supplyable option keys per verb (excludes positional-owned keys).
|
|
@@ -139,9 +180,9 @@ export interface OutputOptions {
|
|
|
139
180
|
* positional-owned keys equals the contract `operationOptionKeys(metadata)`.
|
|
140
181
|
*/
|
|
141
182
|
export declare const VERB_OPTION_KEYS: {
|
|
142
|
-
readonly convert: readonly ["quality", "background", "crf", "trim_start", "trim_end", "fps", "width", "max_colors", "loop", "dither", "bitrate", "pages", "dpi"];
|
|
143
|
-
readonly thumbnail: readonly ["width", "height", "fit", "format", "quality", "timestamp", "source", "page"];
|
|
183
|
+
readonly convert: readonly ["quality", "background", "crf", "trim_start", "trim_end", "fps", "width", "height", "fit", "metadata", "color_profile", "auto_orient", "max_colors", "loop", "dither", "bitrate", "pages", "dpi"];
|
|
184
|
+
readonly thumbnail: readonly ["width", "height", "fit", "format", "quality", "background", "timestamp", "source", "page"];
|
|
144
185
|
readonly textWatermark: readonly ["font_size", "color", "font_family", "rotation", "watermark_mode", "tile_spacing", "anchor", "margin_x", "margin_y", "opacity"];
|
|
145
186
|
readonly watermark: readonly ["anchor", "margin_x", "margin_y", "opacity", "overlay_width"];
|
|
146
|
-
readonly output: readonly ["quality", "width", "height", "fit", "background", "progressive", "optimization_level", "avif_speed", "metadata", "
|
|
187
|
+
readonly output: readonly ["quality", "quality_preset", "encoding_mode", "target_size_bytes", "chroma_subsampling", "width", "height", "fit", "background", "progressive", "optimization_level", "avif_speed", "metadata", "color_profile", "auto_orient", "lossless"];
|
|
147
188
|
};
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
* Mirrored by the PHP array-shape docblocks — keep in lockstep.
|
|
16
16
|
*/
|
|
17
17
|
const CONVERT_OPTION_KEYS = [
|
|
18
|
-
'quality', 'background', 'crf', 'trim_start', 'trim_end', 'fps', 'width',
|
|
19
|
-
'max_colors', 'loop', 'dither', 'bitrate', 'pages', 'dpi',
|
|
18
|
+
'quality', 'background', 'crf', 'trim_start', 'trim_end', 'fps', 'width', 'height', 'fit', 'metadata',
|
|
19
|
+
'color_profile', 'auto_orient', 'max_colors', 'loop', 'dither', 'bitrate', 'pages', 'dpi',
|
|
20
20
|
];
|
|
21
21
|
const THUMBNAIL_OPTION_KEYS = [
|
|
22
|
-
'width', 'height', 'fit', 'format', 'quality', 'timestamp', 'source', 'page',
|
|
22
|
+
'width', 'height', 'fit', 'format', 'quality', 'background', 'timestamp', 'source', 'page',
|
|
23
23
|
];
|
|
24
24
|
const TEXT_WATERMARK_OPTION_KEYS = [
|
|
25
25
|
'font_size', 'color', 'font_family', 'rotation', 'watermark_mode',
|
|
@@ -29,8 +29,9 @@ const WATERMARK_OPTION_KEYS = [
|
|
|
29
29
|
'anchor', 'margin_x', 'margin_y', 'opacity', 'overlay_width',
|
|
30
30
|
];
|
|
31
31
|
const OUTPUT_OPTION_KEYS = [
|
|
32
|
-
'quality', '
|
|
33
|
-
'
|
|
32
|
+
'quality', 'quality_preset', 'encoding_mode', 'target_size_bytes', 'chroma_subsampling', 'width', 'height', 'fit',
|
|
33
|
+
'background', 'progressive', 'optimization_level', 'avif_speed', 'metadata',
|
|
34
|
+
'color_profile', 'auto_orient', 'lossless',
|
|
34
35
|
];
|
|
35
36
|
const _convertKeysMatch = true;
|
|
36
37
|
const _thumbnailKeysMatch = true;
|
|
@@ -9,8 +9,8 @@ import { type OperationMetadata } from '@giveitsmaller/contracts/operations';
|
|
|
9
9
|
* sidecars (the same contract-anchored source the wire-key conformance guard
|
|
10
10
|
* uses), so it can never silently drift from the contract.
|
|
11
11
|
*
|
|
12
|
-
* SCOPE: `convert` / `thumbnail` / `textWatermark` / `watermark`
|
|
13
|
-
* is deliberately EXCLUDED — its bag legitimately carries SDK-only keys
|
|
12
|
+
* SCOPE: `convert` / `thumbnail` / `textWatermark` / `watermark` / `output`
|
|
13
|
+
* only. `compress` is deliberately EXCLUDED — its bag legitimately carries SDK-only keys
|
|
14
14
|
* (`optimize`, `presetOverrides`) and camelCase resolver aliases (`targetSize`,
|
|
15
15
|
* `outputFormat`) that are not `operationOptionKeys(compressMetadata)`; it has its
|
|
16
16
|
* own `unknown_field` validation through the preset resolver.
|
|
@@ -11,8 +11,8 @@ import { VERB_OPTION_KEYS } from './option_types.js';
|
|
|
11
11
|
* sidecars (the same contract-anchored source the wire-key conformance guard
|
|
12
12
|
* uses), so it can never silently drift from the contract.
|
|
13
13
|
*
|
|
14
|
-
* SCOPE: `convert` / `thumbnail` / `textWatermark` / `watermark`
|
|
15
|
-
* is deliberately EXCLUDED — its bag legitimately carries SDK-only keys
|
|
14
|
+
* SCOPE: `convert` / `thumbnail` / `textWatermark` / `watermark` / `output`
|
|
15
|
+
* only. `compress` is deliberately EXCLUDED — its bag legitimately carries SDK-only keys
|
|
16
16
|
* (`optimize`, `presetOverrides`) and camelCase resolver aliases (`targetSize`,
|
|
17
17
|
* `outputFormat`) that are not `operationOptionKeys(compressMetadata)`; it has its
|
|
18
18
|
* own `unknown_field` validation through the preset resolver.
|
|
@@ -9,7 +9,7 @@ import { type PresetDefaults, type PresetMedia, type PresetOp } from './presets/
|
|
|
9
9
|
* construction. Previously a hand-typed literal that the v2.73.0 regen had to
|
|
10
10
|
* bump manually (yREs0srv).
|
|
11
11
|
*/
|
|
12
|
-
export declare const PRESET_VERSION: "1.
|
|
12
|
+
export declare const PRESET_VERSION: "1.6";
|
|
13
13
|
/**
|
|
14
14
|
* Inputs to {@link resolveCompressOptions}. `media` selects which leaf
|
|
15
15
|
* DTO drives sdkDefault + clientDefault lookups + invalid-combo
|
|
@@ -63,7 +63,6 @@ const WIRE_ALIASES = Object.freeze({
|
|
|
63
63
|
sampleRate: 'sample_rate',
|
|
64
64
|
audioCodec: 'audio_codec',
|
|
65
65
|
audioBitrate: 'audio_bitrate',
|
|
66
|
-
imageQuality: 'image_quality',
|
|
67
66
|
stripMacros: 'strip_macros',
|
|
68
67
|
stripHiddenData: 'strip_hidden_data',
|
|
69
68
|
stripUnusedFonts: 'strip_unused_fonts',
|
|
@@ -254,9 +253,9 @@ const MEDIA_FIELDS = Object.freeze({
|
|
|
254
253
|
audio: new Set(['bitrate', 'channels', 'sampleRate', 'normalize']),
|
|
255
254
|
video: new Set(['codec', 'targetSize', 'crf', 'preset', 'width', 'height', 'fit', 'fps', 'faststart', 'audioCodec', 'audioBitrate']),
|
|
256
255
|
document_pdf: new Set(['profile', 'grayscale']),
|
|
257
|
-
document_office: new Set(['
|
|
258
|
-
document_odf: new Set(['
|
|
259
|
-
document_epub: new Set(['
|
|
256
|
+
document_office: new Set(['stripMacros', 'stripHiddenData', 'stripUnusedFonts']),
|
|
257
|
+
document_odf: new Set(['stripMetadata', 'stripUnusedStyles']),
|
|
258
|
+
document_epub: new Set(['fontSubsetting', 'stripUnusedCss']),
|
|
260
259
|
});
|
|
261
260
|
function detectMismatchedOverrides(media, overrides) {
|
|
262
261
|
const expected = MEDIA_FIELDS[media];
|
|
@@ -323,9 +322,9 @@ export const KNOWN_WIRE_FIELDS = Object.freeze({
|
|
|
323
322
|
audio: new Set(['bitrate', 'channels', 'sample_rate', 'normalize', 'trim_start', 'trim_end']),
|
|
324
323
|
video: new Set(['codec', 'encoding_mode', 'crf', 'target_size_bytes', 'preset', 'width', 'height', 'fit', 'fps', 'faststart', 'audio_codec', 'audio_bitrate', 'trim_start', 'trim_end']),
|
|
325
324
|
document_pdf: new Set(['profile', 'grayscale']),
|
|
326
|
-
document_office: new Set(['
|
|
327
|
-
document_odf: new Set(['
|
|
328
|
-
document_epub: new Set(['
|
|
325
|
+
document_office: new Set(['strip_macros', 'strip_hidden_data', 'strip_unused_fonts']),
|
|
326
|
+
document_odf: new Set(['strip_metadata', 'strip_unused_styles']),
|
|
327
|
+
document_epub: new Set(['font_subsetting', 'strip_unused_css']),
|
|
329
328
|
});
|
|
330
329
|
function validateMerged(media, merged, explicitKeys, winners) {
|
|
331
330
|
// Unknown-field defence-in-depth: every key must belong to the
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { OptimizeFor } from '../../generated/sdk_spec/enums.js';
|
|
2
2
|
export interface DocumentEpubCompressPresetOptionsInput {
|
|
3
|
-
readonly imageQuality?: number;
|
|
4
3
|
readonly fontSubsetting?: boolean;
|
|
5
4
|
readonly stripUnusedCss?: boolean;
|
|
6
5
|
}
|
|
7
6
|
export declare class DocumentEpubCompressPresetOptions {
|
|
8
|
-
readonly imageQuality?: number;
|
|
9
7
|
readonly fontSubsetting?: boolean;
|
|
10
8
|
readonly stripUnusedCss?: boolean;
|
|
11
9
|
private constructor();
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
// T4a — DocumentEpubCompressPresetOptions leaf DTO.
|
|
2
2
|
//
|
|
3
|
-
// Field set per ticket VhIj4S7T: EPUB =
|
|
4
|
-
// (
|
|
3
|
+
// Field set per ticket VhIj4S7T: EPUB = 2 fields
|
|
4
|
+
// (fontSubsetting, stripUnusedCss). Primitives only.
|
|
5
5
|
import { shippedDefaultsFor as f3ShippedDefaultsFor } from '../../generated/sdk_spec/presets.js';
|
|
6
6
|
export class DocumentEpubCompressPresetOptions {
|
|
7
|
-
imageQuality;
|
|
8
7
|
fontSubsetting;
|
|
9
8
|
stripUnusedCss;
|
|
10
9
|
constructor(input) {
|
|
11
|
-
if (input.imageQuality !== undefined)
|
|
12
|
-
this.imageQuality = input.imageQuality;
|
|
13
10
|
if (input.fontSubsetting !== undefined)
|
|
14
11
|
this.fontSubsetting = input.fontSubsetting;
|
|
15
12
|
if (input.stripUnusedCss !== undefined)
|
|
@@ -23,8 +20,6 @@ export class DocumentEpubCompressPresetOptions {
|
|
|
23
20
|
const cell = f3ShippedDefaultsFor('document_epub_compress', level);
|
|
24
21
|
const input = {};
|
|
25
22
|
const mut = input;
|
|
26
|
-
if ('imageQuality' in cell)
|
|
27
|
-
mut.imageQuality = cell.imageQuality;
|
|
28
23
|
if ('fontSubsetting' in cell)
|
|
29
24
|
mut.fontSubsetting = cell.fontSubsetting;
|
|
30
25
|
if ('stripUnusedCss' in cell)
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { OptimizeFor } from '../../generated/sdk_spec/enums.js';
|
|
2
2
|
export interface DocumentOdfCompressPresetOptionsInput {
|
|
3
|
-
readonly imageQuality?: number;
|
|
4
3
|
readonly stripMetadata?: boolean;
|
|
5
4
|
readonly stripUnusedStyles?: boolean;
|
|
6
5
|
}
|
|
7
6
|
export declare class DocumentOdfCompressPresetOptions {
|
|
8
|
-
readonly imageQuality?: number;
|
|
9
7
|
readonly stripMetadata?: boolean;
|
|
10
8
|
readonly stripUnusedStyles?: boolean;
|
|
11
9
|
private constructor();
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
// T4a — DocumentOdfCompressPresetOptions leaf DTO.
|
|
2
2
|
//
|
|
3
|
-
// Field set per ticket VhIj4S7T: ODF =
|
|
4
|
-
// (
|
|
3
|
+
// Field set per ticket VhIj4S7T: ODF = 2 fields
|
|
4
|
+
// (stripMetadata, stripUnusedStyles). Primitives only.
|
|
5
5
|
import { shippedDefaultsFor as f3ShippedDefaultsFor } from '../../generated/sdk_spec/presets.js';
|
|
6
6
|
export class DocumentOdfCompressPresetOptions {
|
|
7
|
-
imageQuality;
|
|
8
7
|
stripMetadata;
|
|
9
8
|
stripUnusedStyles;
|
|
10
9
|
constructor(input) {
|
|
11
|
-
if (input.imageQuality !== undefined)
|
|
12
|
-
this.imageQuality = input.imageQuality;
|
|
13
10
|
if (input.stripMetadata !== undefined)
|
|
14
11
|
this.stripMetadata = input.stripMetadata;
|
|
15
12
|
if (input.stripUnusedStyles !== undefined)
|
|
@@ -23,8 +20,6 @@ export class DocumentOdfCompressPresetOptions {
|
|
|
23
20
|
const cell = f3ShippedDefaultsFor('document_odf_compress', level);
|
|
24
21
|
const input = {};
|
|
25
22
|
const mut = input;
|
|
26
|
-
if ('imageQuality' in cell)
|
|
27
|
-
mut.imageQuality = cell.imageQuality;
|
|
28
23
|
if ('stripMetadata' in cell)
|
|
29
24
|
mut.stripMetadata = cell.stripMetadata;
|
|
30
25
|
if ('stripUnusedStyles' in cell)
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { OptimizeFor } from '../../generated/sdk_spec/enums.js';
|
|
2
2
|
export interface DocumentOfficeCompressPresetOptionsInput {
|
|
3
|
-
readonly imageQuality?: number;
|
|
4
3
|
readonly stripMacros?: boolean;
|
|
5
4
|
readonly stripHiddenData?: boolean;
|
|
6
5
|
readonly stripUnusedFonts?: boolean;
|
|
7
6
|
}
|
|
8
7
|
export declare class DocumentOfficeCompressPresetOptions {
|
|
9
|
-
readonly imageQuality?: number;
|
|
10
8
|
readonly stripMacros?: boolean;
|
|
11
9
|
readonly stripHiddenData?: boolean;
|
|
12
10
|
readonly stripUnusedFonts?: boolean;
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
// T4a — DocumentOfficeCompressPresetOptions leaf DTO.
|
|
2
2
|
//
|
|
3
|
-
// Field set per ticket VhIj4S7T: office =
|
|
4
|
-
// (
|
|
3
|
+
// Field set per ticket VhIj4S7T: office = 3 fields
|
|
4
|
+
// (stripMacros, stripHiddenData, stripUnusedFonts).
|
|
5
5
|
// All primitive values — no enum translation needed.
|
|
6
6
|
import { shippedDefaultsFor as f3ShippedDefaultsFor } from '../../generated/sdk_spec/presets.js';
|
|
7
7
|
export class DocumentOfficeCompressPresetOptions {
|
|
8
|
-
imageQuality;
|
|
9
8
|
stripMacros;
|
|
10
9
|
stripHiddenData;
|
|
11
10
|
stripUnusedFonts;
|
|
12
11
|
constructor(input) {
|
|
13
|
-
if (input.imageQuality !== undefined)
|
|
14
|
-
this.imageQuality = input.imageQuality;
|
|
15
12
|
if (input.stripMacros !== undefined)
|
|
16
13
|
this.stripMacros = input.stripMacros;
|
|
17
14
|
if (input.stripHiddenData !== undefined)
|
|
@@ -27,8 +24,6 @@ export class DocumentOfficeCompressPresetOptions {
|
|
|
27
24
|
const cell = f3ShippedDefaultsFor('document_office_compress', level);
|
|
28
25
|
const input = {};
|
|
29
26
|
const mut = input;
|
|
30
|
-
if ('imageQuality' in cell)
|
|
31
|
-
mut.imageQuality = cell.imageQuality;
|
|
32
27
|
if ('stripMacros' in cell)
|
|
33
28
|
mut.stripMacros = cell.stripMacros;
|
|
34
29
|
if ('stripHiddenData' in cell)
|
package/dist/file-first.d.ts
CHANGED
|
@@ -57,6 +57,21 @@ export interface OutputFile {
|
|
|
57
57
|
readonly filename: string;
|
|
58
58
|
readonly sizeBytes: number;
|
|
59
59
|
readonly operation: string;
|
|
60
|
+
/**
|
|
61
|
+
* For a `target_size` encode: the quality the encode-measure loop settled
|
|
62
|
+
* on. Projected from the generated {@link OperationDownload.chosenQuality};
|
|
63
|
+
* undefined (omitted) for non-target-size outputs. Pairs with
|
|
64
|
+
* {@link targetSizeMet}.
|
|
65
|
+
*/
|
|
66
|
+
readonly chosenQuality?: number;
|
|
67
|
+
/**
|
|
68
|
+
* For a `target_size` encode: whether the output landed at or under the
|
|
69
|
+
* requested byte target. `false` is an honest best-effort outcome (target
|
|
70
|
+
* unreachable at min quality), NOT a failure. Projected from the generated
|
|
71
|
+
* {@link OperationDownload.targetSizeMet}; undefined for non-target-size
|
|
72
|
+
* outputs.
|
|
73
|
+
*/
|
|
74
|
+
readonly targetSizeMet?: boolean;
|
|
60
75
|
}
|
|
61
76
|
/**
|
|
62
77
|
* One succeeded entry in {@link RunResult.succeeded}: a single input's
|
|
@@ -101,6 +116,10 @@ export interface Manifest {
|
|
|
101
116
|
* - `ok`: true iff `failed` is empty. (A boolean — the partition lists are
|
|
102
117
|
* `succeeded`/`failed`; resolves the design doc's `ok` bool-vs-list
|
|
103
118
|
* contradiction.)
|
|
119
|
+
* - `targetSizeMissed`: derived target-size signal — undefined when no output
|
|
120
|
+
* reports a target-size outcome (not a target_size run); otherwise true iff
|
|
121
|
+
* some artifact has `targetSizeMet === false`. Omitted from the JSON when
|
|
122
|
+
* undefined so non-target-size runs keep the common-case shape.
|
|
104
123
|
* - `state`: lifecycle state (`completed` | `failed` | ...). Named `state`,
|
|
105
124
|
* NOT `status`, matching the file-first `StatusSnapshot.state`.
|
|
106
125
|
* - sinks fetch via the injected {@link Downloader}; a result with no
|
|
@@ -117,6 +136,14 @@ export declare class RunResult {
|
|
|
117
136
|
readonly url?: string;
|
|
118
137
|
/** True iff {@link failed} is empty. */
|
|
119
138
|
readonly ok: boolean;
|
|
139
|
+
/**
|
|
140
|
+
* Whether any output missed its requested byte target. Derived from the
|
|
141
|
+
* per-output {@link OutputFile.targetSizeMet}: undefined when NO artifact
|
|
142
|
+
* reports a target-size outcome (every `targetSizeMet` undefined — not a
|
|
143
|
+
* target_size run); otherwise true iff some artifact has
|
|
144
|
+
* `targetSizeMet === false`.
|
|
145
|
+
*/
|
|
146
|
+
readonly targetSizeMissed?: boolean;
|
|
120
147
|
constructor(workflowId: string, state: string, artifacts: readonly OutputFile[], succeeded: readonly ItemResult[], failed: readonly ItemFailure[], downloader?: Downloader | undefined);
|
|
121
148
|
/**
|
|
122
149
|
* Address a succeeded input by the `key:` given to `file()`. Duplicate keys
|
|
@@ -143,16 +170,18 @@ export declare class RunResult {
|
|
|
143
170
|
failOnPartial?: boolean;
|
|
144
171
|
}): Promise<Manifest>;
|
|
145
172
|
/**
|
|
146
|
-
* Plain-object projection. Field ORDER (workflowId, state, ok,
|
|
147
|
-
* artifacts, succeeded, failed) is fixed to match
|
|
148
|
-
* reference so JSON-string parity holds (FF1 shape
|
|
149
|
-
* fixture). `url`
|
|
150
|
-
*
|
|
173
|
+
* Plain-object projection. Field ORDER (workflowId, state, ok,
|
|
174
|
+
* targetSizeMissed?, url?, artifacts, succeeded, failed) is fixed to match
|
|
175
|
+
* the PHP `toArray()` reference so JSON-string parity holds (FF1 shape
|
|
176
|
+
* assertion + FF2b harness fixture). `targetSizeMissed` + `url` are omitted
|
|
177
|
+
* entirely when undefined — `JSON.stringify` then produces the identical
|
|
178
|
+
* shape to PHP's omit-when-null `toArray()`.
|
|
151
179
|
*/
|
|
152
180
|
toJSON(): {
|
|
153
181
|
workflowId: string;
|
|
154
182
|
state: string;
|
|
155
183
|
ok: boolean;
|
|
184
|
+
targetSizeMissed?: boolean;
|
|
156
185
|
url?: string;
|
|
157
186
|
artifacts: readonly OutputFile[];
|
|
158
187
|
succeeded: readonly {
|
|
@@ -536,6 +565,14 @@ export declare const WATERMARK_CAPABILITY: {
|
|
|
536
565
|
readonly mimes: readonly ["image/gif"];
|
|
537
566
|
readonly availability: "planned";
|
|
538
567
|
};
|
|
568
|
+
readonly image_tiff: {
|
|
569
|
+
readonly mimes: readonly ["image/tiff"];
|
|
570
|
+
readonly availability: "stable";
|
|
571
|
+
};
|
|
572
|
+
readonly image_bmp: {
|
|
573
|
+
readonly mimes: readonly ["image/bmp"];
|
|
574
|
+
readonly availability: "stable";
|
|
575
|
+
};
|
|
539
576
|
};
|
|
540
577
|
readonly video_watermark: {
|
|
541
578
|
readonly video: {
|
package/dist/file-first.js
CHANGED
|
@@ -40,6 +40,10 @@ import { Handle } from './handle.js';
|
|
|
40
40
|
* - `ok`: true iff `failed` is empty. (A boolean — the partition lists are
|
|
41
41
|
* `succeeded`/`failed`; resolves the design doc's `ok` bool-vs-list
|
|
42
42
|
* contradiction.)
|
|
43
|
+
* - `targetSizeMissed`: derived target-size signal — undefined when no output
|
|
44
|
+
* reports a target-size outcome (not a target_size run); otherwise true iff
|
|
45
|
+
* some artifact has `targetSizeMet === false`. Omitted from the JSON when
|
|
46
|
+
* undefined so non-target-size runs keep the common-case shape.
|
|
43
47
|
* - `state`: lifecycle state (`completed` | `failed` | ...). Named `state`,
|
|
44
48
|
* NOT `status`, matching the file-first `StatusSnapshot.state`.
|
|
45
49
|
* - sinks fetch via the injected {@link Downloader}; a result with no
|
|
@@ -56,6 +60,14 @@ export class RunResult {
|
|
|
56
60
|
url;
|
|
57
61
|
/** True iff {@link failed} is empty. */
|
|
58
62
|
ok;
|
|
63
|
+
/**
|
|
64
|
+
* Whether any output missed its requested byte target. Derived from the
|
|
65
|
+
* per-output {@link OutputFile.targetSizeMet}: undefined when NO artifact
|
|
66
|
+
* reports a target-size outcome (every `targetSizeMet` undefined — not a
|
|
67
|
+
* target_size run); otherwise true iff some artifact has
|
|
68
|
+
* `targetSizeMet === false`.
|
|
69
|
+
*/
|
|
70
|
+
targetSizeMissed;
|
|
59
71
|
constructor(workflowId, state, artifacts, succeeded, failed, downloader) {
|
|
60
72
|
this.workflowId = workflowId;
|
|
61
73
|
this.state = state;
|
|
@@ -65,6 +77,9 @@ export class RunResult {
|
|
|
65
77
|
this.downloader = downloader;
|
|
66
78
|
this.url = artifacts.length === 1 ? artifacts[0].url : undefined;
|
|
67
79
|
this.ok = failed.length === 0;
|
|
80
|
+
this.targetSizeMissed = artifacts.every((a) => a.targetSizeMet === undefined)
|
|
81
|
+
? undefined
|
|
82
|
+
: artifacts.some((a) => a.targetSizeMet === false);
|
|
68
83
|
}
|
|
69
84
|
/**
|
|
70
85
|
* Address a succeeded input by the `key:` given to `file()`. Duplicate keys
|
|
@@ -134,20 +149,26 @@ export class RunResult {
|
|
|
134
149
|
return { paths };
|
|
135
150
|
}
|
|
136
151
|
/**
|
|
137
|
-
* Plain-object projection. Field ORDER (workflowId, state, ok,
|
|
138
|
-
* artifacts, succeeded, failed) is fixed to match
|
|
139
|
-
* reference so JSON-string parity holds (FF1 shape
|
|
140
|
-
* fixture). `url`
|
|
141
|
-
*
|
|
152
|
+
* Plain-object projection. Field ORDER (workflowId, state, ok,
|
|
153
|
+
* targetSizeMissed?, url?, artifacts, succeeded, failed) is fixed to match
|
|
154
|
+
* the PHP `toArray()` reference so JSON-string parity holds (FF1 shape
|
|
155
|
+
* assertion + FF2b harness fixture). `targetSizeMissed` + `url` are omitted
|
|
156
|
+
* entirely when undefined — `JSON.stringify` then produces the identical
|
|
157
|
+
* shape to PHP's omit-when-null `toArray()`.
|
|
142
158
|
*/
|
|
143
159
|
toJSON() {
|
|
144
|
-
// Re-project each OutputFile to exactly its
|
|
160
|
+
// Re-project each OutputFile to exactly its known fields so structurally
|
|
145
161
|
// compatible inputs carrying extra properties can't leak into the JSON.
|
|
162
|
+
// The target-size fields (chosenQuality/targetSizeMet) are OMITTED when
|
|
163
|
+
// undefined, mirroring PHP's omit-when-null so non-target-size outputs
|
|
164
|
+
// stay byte-identical across languages.
|
|
146
165
|
const file = (o) => ({
|
|
147
166
|
url: o.url,
|
|
148
167
|
filename: o.filename,
|
|
149
168
|
sizeBytes: o.sizeBytes,
|
|
150
169
|
operation: o.operation,
|
|
170
|
+
...(o.chosenQuality !== undefined ? { chosenQuality: o.chosenQuality } : {}),
|
|
171
|
+
...(o.targetSizeMet !== undefined ? { targetSizeMet: o.targetSizeMet } : {}),
|
|
151
172
|
});
|
|
152
173
|
const rest = {
|
|
153
174
|
artifacts: this.artifacts.map(file),
|
|
@@ -164,13 +185,18 @@ export class RunResult {
|
|
|
164
185
|
}),
|
|
165
186
|
};
|
|
166
187
|
const head = { workflowId: this.workflowId, state: this.state, ok: this.ok };
|
|
167
|
-
// Insert `
|
|
168
|
-
//
|
|
169
|
-
//
|
|
170
|
-
//
|
|
188
|
+
// Insert `targetSizeMissed` immediately after `ok` (before `url`) when
|
|
189
|
+
// present, then `url` BETWEEN it and artifacts, matching the PHP toArray()
|
|
190
|
+
// field order (workflowId, state, ok, targetSizeMissed?, url?, artifacts,
|
|
191
|
+
// ...) so JSON-string parity holds. Both are omitted entirely when
|
|
192
|
+
// undefined (PHP omits null), so `JSON.stringify` produces the identical
|
|
193
|
+
// shape.
|
|
194
|
+
const headWithMissed = this.targetSizeMissed === undefined
|
|
195
|
+
? head
|
|
196
|
+
: { ...head, targetSizeMissed: this.targetSizeMissed };
|
|
171
197
|
return this.url === undefined
|
|
172
|
-
? { ...
|
|
173
|
-
: { ...
|
|
198
|
+
? { ...headWithMissed, ...rest }
|
|
199
|
+
: { ...headWithMissed, url: this.url, ...rest };
|
|
174
200
|
}
|
|
175
201
|
requireDownloader() {
|
|
176
202
|
if (this.downloader === undefined) {
|
|
@@ -200,6 +226,10 @@ export function projectDownloadsToRunResult(workflowId, finalStatus, jobDownload
|
|
|
200
226
|
filename: f.filename,
|
|
201
227
|
sizeBytes: f.sizeBytes,
|
|
202
228
|
operation: f.operation,
|
|
229
|
+
// Omit-when-absent on the LIVE OutputFile too (not just toJSON): a
|
|
230
|
+
// non-target-size output carries no chosenQuality/targetSizeMet key.
|
|
231
|
+
...(f.chosenQuality !== undefined ? { chosenQuality: f.chosenQuality } : {}),
|
|
232
|
+
...(f.targetSizeMet !== undefined ? { targetSizeMet: f.targetSizeMet } : {}),
|
|
203
233
|
});
|
|
204
234
|
}
|
|
205
235
|
}
|
|
@@ -259,6 +289,10 @@ export function projectMultiJobToRunResult(workflowId, finalStatus, jobDownloads
|
|
|
259
289
|
filename: f.filename,
|
|
260
290
|
sizeBytes: f.sizeBytes,
|
|
261
291
|
operation: f.operation,
|
|
292
|
+
// Omit-when-absent on the LIVE OutputFile too (mirrors toJSON + the
|
|
293
|
+
// single-job projector).
|
|
294
|
+
...(f.chosenQuality !== undefined ? { chosenQuality: f.chosenQuality } : {}),
|
|
295
|
+
...(f.targetSizeMet !== undefined ? { targetSizeMet: f.targetSizeMet } : {}),
|
|
262
296
|
}));
|
|
263
297
|
// The flat artifacts[] keeps every job's outputs in job order.
|
|
264
298
|
artifacts.push(...outputs);
|
|
@@ -1055,6 +1089,8 @@ export const WATERMARK_CAPABILITY = {
|
|
|
1055
1089
|
image_watermark: {
|
|
1056
1090
|
image: { mimes: ['image/jpeg', 'image/png', 'image/webp'], availability: 'stable' },
|
|
1057
1091
|
image_gif: { mimes: ['image/gif'], availability: 'planned' },
|
|
1092
|
+
image_tiff: { mimes: ['image/tiff'], availability: 'stable' },
|
|
1093
|
+
image_bmp: { mimes: ['image/bmp'], availability: 'stable' },
|
|
1058
1094
|
},
|
|
1059
1095
|
video_watermark: {
|
|
1060
1096
|
video: { mimes: ['video/mp4', 'video/webm'], availability: 'beta' },
|
|
@@ -10,8 +10,9 @@ export declare const ImageFormat: {
|
|
|
10
10
|
};
|
|
11
11
|
export type ImageFormat = typeof ImageFormat[keyof typeof ImageFormat];
|
|
12
12
|
export declare const ImageMetadataPolicy: {
|
|
13
|
-
readonly
|
|
13
|
+
readonly Strip: "strip";
|
|
14
14
|
readonly Keep: "keep";
|
|
15
|
+
readonly All: "all";
|
|
15
16
|
};
|
|
16
17
|
export type ImageMetadataPolicy = typeof ImageMetadataPolicy[keyof typeof ImageMetadataPolicy];
|
|
17
18
|
export declare const VideoCodec: {
|
|
@@ -88,8 +89,9 @@ export declare const ERGONOMIC_ENUMS: {
|
|
|
88
89
|
readonly Webp: "webp";
|
|
89
90
|
};
|
|
90
91
|
readonly ImageMetadataPolicy: {
|
|
91
|
-
readonly
|
|
92
|
+
readonly Strip: "strip";
|
|
92
93
|
readonly Keep: "keep";
|
|
94
|
+
readonly All: "all";
|
|
93
95
|
};
|
|
94
96
|
readonly VideoCodec: {
|
|
95
97
|
readonly H264: "h264";
|
|
@@ -13,15 +13,21 @@ export const ImageFormat = {
|
|
|
13
13
|
Webp: "webp",
|
|
14
14
|
};
|
|
15
15
|
// Image metadata handling (compress.image, optimiser/same_format route):
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
16
|
+
// Strip = remove all EXIF/IPTC/XMP (default, smallest file) — the canonical
|
|
17
|
+
// strip token (renamed from `all` 2026-06-23; `all` reading as
|
|
18
|
+
// "strip all" was counterintuitive).
|
|
19
|
+
// Keep = preserve EXIF/ICC/XMP — worker-proven on the libcaesium formats
|
|
20
|
+
// (JPEG/PNG/WebP/GIF/TIFF; lambdas PR #260, un-parked 2026-06-23).
|
|
21
|
+
// All = DEPRECATED alias of Strip (still accepted on the wire, emits
|
|
22
|
+
// Deprecation/Sunset; the API lowers `strip`→`all` at the worker
|
|
23
|
+
// boundary). Migrate to Strip.
|
|
19
24
|
// Keep is NOT available for AVIF (ravif) / SVG (SVGO) — those re-encode from
|
|
20
25
|
// pixels and cannot preserve metadata, so the worker rejects it there (the
|
|
21
|
-
// `metadata` enum is narrowed to [all] on those groups).
|
|
26
|
+
// `metadata` enum is narrowed to [strip, all] on those groups).
|
|
22
27
|
export const ImageMetadataPolicy = {
|
|
23
|
-
|
|
28
|
+
Strip: "strip",
|
|
24
29
|
Keep: "keep",
|
|
30
|
+
All: "all",
|
|
25
31
|
};
|
|
26
32
|
// Video codec. H264 = widest compatibility; H265/Av1 = better compression but slower.
|
|
27
33
|
export const VideoCodec = {
|
|
@@ -5,17 +5,17 @@ export const PRESETS = Object.freeze({
|
|
|
5
5
|
"image_compress": Object.freeze({
|
|
6
6
|
Size: Object.freeze({
|
|
7
7
|
"quality": 65,
|
|
8
|
-
"metadata": "
|
|
8
|
+
"metadata": "Strip",
|
|
9
9
|
"outputFormat": "Original",
|
|
10
10
|
}),
|
|
11
11
|
Balanced: Object.freeze({
|
|
12
12
|
"quality": 80,
|
|
13
|
-
"metadata": "
|
|
13
|
+
"metadata": "Strip",
|
|
14
14
|
"outputFormat": "Original",
|
|
15
15
|
}),
|
|
16
16
|
Quality: Object.freeze({
|
|
17
17
|
"quality": 92,
|
|
18
|
-
"metadata": "
|
|
18
|
+
"metadata": "Strip",
|
|
19
19
|
"outputFormat": "Original",
|
|
20
20
|
}),
|
|
21
21
|
}),
|
|
@@ -66,19 +66,16 @@ export const PRESETS = Object.freeze({
|
|
|
66
66
|
}),
|
|
67
67
|
"document_office_compress": Object.freeze({
|
|
68
68
|
Size: Object.freeze({
|
|
69
|
-
"imageQuality": 60,
|
|
70
69
|
"stripMacros": true,
|
|
71
70
|
"stripHiddenData": true,
|
|
72
71
|
"stripUnusedFonts": true,
|
|
73
72
|
}),
|
|
74
73
|
Balanced: Object.freeze({
|
|
75
|
-
"imageQuality": 80,
|
|
76
74
|
"stripMacros": true,
|
|
77
75
|
"stripHiddenData": false,
|
|
78
76
|
"stripUnusedFonts": false,
|
|
79
77
|
}),
|
|
80
78
|
Quality: Object.freeze({
|
|
81
|
-
"imageQuality": 92,
|
|
82
79
|
"stripMacros": false,
|
|
83
80
|
"stripHiddenData": false,
|
|
84
81
|
"stripUnusedFonts": false,
|
|
@@ -86,34 +83,28 @@ export const PRESETS = Object.freeze({
|
|
|
86
83
|
}),
|
|
87
84
|
"document_odf_compress": Object.freeze({
|
|
88
85
|
Size: Object.freeze({
|
|
89
|
-
"imageQuality": 60,
|
|
90
86
|
"stripMetadata": true,
|
|
91
87
|
"stripUnusedStyles": true,
|
|
92
88
|
}),
|
|
93
89
|
Balanced: Object.freeze({
|
|
94
|
-
"imageQuality": 80,
|
|
95
90
|
"stripMetadata": true,
|
|
96
91
|
"stripUnusedStyles": false,
|
|
97
92
|
}),
|
|
98
93
|
Quality: Object.freeze({
|
|
99
|
-
"imageQuality": 92,
|
|
100
94
|
"stripMetadata": false,
|
|
101
95
|
"stripUnusedStyles": false,
|
|
102
96
|
}),
|
|
103
97
|
}),
|
|
104
98
|
"document_epub_compress": Object.freeze({
|
|
105
99
|
Size: Object.freeze({
|
|
106
|
-
"imageQuality": 60,
|
|
107
100
|
"fontSubsetting": true,
|
|
108
101
|
"stripUnusedCss": true,
|
|
109
102
|
}),
|
|
110
103
|
Balanced: Object.freeze({
|
|
111
|
-
"imageQuality": 80,
|
|
112
104
|
"fontSubsetting": true,
|
|
113
105
|
"stripUnusedCss": false,
|
|
114
106
|
}),
|
|
115
107
|
Quality: Object.freeze({
|
|
116
|
-
"imageQuality": 92,
|
|
117
108
|
"fontSubsetting": false,
|
|
118
109
|
"stripUnusedCss": false,
|
|
119
110
|
}),
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export declare const SDK_SPEC_VERSION: "2.
|
|
2
|
-
export declare const PRESET_VERSION: "1.
|
|
3
|
-
export declare const PRESET_CONFIG_HASH: "sha256:
|
|
1
|
+
export declare const SDK_SPEC_VERSION: "2.2.0";
|
|
2
|
+
export declare const PRESET_VERSION: "1.6";
|
|
3
|
+
export declare const PRESET_CONFIG_HASH: "sha256:0fe215aede1da13430380384c58226d074c3b8344c091efc53e097c2930a34f7";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// CODE GENERATED — DO NOT EDIT.
|
|
2
2
|
// Source: compression_contracts/sdk-spec/ (see sdk-spec/README.md).
|
|
3
3
|
// Regenerate with: scripts/generate.py.
|
|
4
|
-
export const SDK_SPEC_VERSION = "2.
|
|
5
|
-
export const PRESET_VERSION = "1.
|
|
6
|
-
export const PRESET_CONFIG_HASH = "sha256:
|
|
4
|
+
export const SDK_SPEC_VERSION = "2.2.0";
|
|
5
|
+
export const PRESET_VERSION = "1.6";
|
|
6
|
+
export const PRESET_CONFIG_HASH = "sha256:0fe215aede1da13430380384c58226d074c3b8344c091efc53e097c2930a34f7";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@giveitsmaller/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "Node.js SDK for the GISL (Give It Smaller) file compression and processing API",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"node": ">=18"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@giveitsmaller/contracts": "^0.
|
|
34
|
+
"@giveitsmaller/contracts": "^0.50.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/node": "^22",
|