@giveitsmaller/sdk 0.18.0 → 0.20.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/_audit.js +12 -0
- package/dist/builder.d.ts +1 -0
- package/dist/client.d.ts +8 -1
- package/dist/client.js +27 -32
- 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 +85 -11
- package/dist/ergonomic/option_types.js +11 -6
- package/dist/ergonomic/option_validation.d.ts +21 -3
- package/dist/ergonomic/option_validation.js +36 -3
- 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/errors.d.ts +57 -1
- package/dist/errors.js +82 -1
- package/dist/file-first.d.ts +195 -8
- package/dist/file-first.js +462 -124
- 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/dist/gisl.d.ts +72 -3
- package/dist/gisl.js +72 -2
- package/dist/index.core.d.ts +8 -6
- package/dist/index.core.js +9 -1
- package/dist/merge.d.ts +12 -0
- package/dist/merge.js +12 -0
- package/dist/retry-metadata.d.ts +37 -0
- package/dist/retry-metadata.js +86 -0
- package/dist/sse.d.ts +2 -1
- package/dist/sse.js +26 -6
- package/dist/types.d.ts +43 -1
- package/package.json +2 -2
package/dist/file-first.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ import { GislItemFailedError } from './errors.js';
|
|
|
13
13
|
import { type ProgressEvent } from './builder.js';
|
|
14
14
|
import type { GislClient } from './client.js';
|
|
15
15
|
import type { OperationDownload, WorkflowStatusResponse } from '@giveitsmaller/contracts/openapi';
|
|
16
|
-
import type { ConvertOptions, ThumbnailOptions, TextWatermarkOptions, WatermarkOptions, OutputOptions, OutputFit } from './ergonomic/option_types.js';
|
|
16
|
+
import type { ConvertOptions, ThumbnailOptions, TransformOptions, TextWatermarkOptions, WatermarkOptions, OutputOptions, OutputFit } from './ergonomic/option_types.js';
|
|
17
17
|
import { OptimizeFor } from './generated/sdk_spec/enums.js';
|
|
18
18
|
import type { PresetDefaults } from './ergonomic/presets/index.js';
|
|
19
19
|
import type { WorkflowCreatePayload } from './types.js';
|
|
@@ -57,6 +57,34 @@ 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;
|
|
75
|
+
/**
|
|
76
|
+
* The measured perceptual quality of an `auto_quality` encode (0-1). Projected
|
|
77
|
+
* from the generated {@link OperationDownload.measuredQuality}; undefined
|
|
78
|
+
* (omitted) when the worker reported no measurement. Pairs with
|
|
79
|
+
* {@link qualityMetric}, which names the metric it was measured on.
|
|
80
|
+
*/
|
|
81
|
+
readonly measuredQuality?: number;
|
|
82
|
+
/**
|
|
83
|
+
* The metric {@link measuredQuality} was measured on (e.g. `ssimulacra2`).
|
|
84
|
+
* Projected from the generated {@link OperationDownload.qualityMetric};
|
|
85
|
+
* undefined when no measurement was reported.
|
|
86
|
+
*/
|
|
87
|
+
readonly qualityMetric?: string;
|
|
60
88
|
}
|
|
61
89
|
/**
|
|
62
90
|
* One succeeded entry in {@link RunResult.succeeded}: a single input's
|
|
@@ -101,6 +129,10 @@ export interface Manifest {
|
|
|
101
129
|
* - `ok`: true iff `failed` is empty. (A boolean — the partition lists are
|
|
102
130
|
* `succeeded`/`failed`; resolves the design doc's `ok` bool-vs-list
|
|
103
131
|
* contradiction.)
|
|
132
|
+
* - `targetSizeMissed`: derived target-size signal — undefined when no output
|
|
133
|
+
* reports a target-size outcome (not a target_size run); otherwise true iff
|
|
134
|
+
* some artifact has `targetSizeMet === false`. Omitted from the JSON when
|
|
135
|
+
* undefined so non-target-size runs keep the common-case shape.
|
|
104
136
|
* - `state`: lifecycle state (`completed` | `failed` | ...). Named `state`,
|
|
105
137
|
* NOT `status`, matching the file-first `StatusSnapshot.state`.
|
|
106
138
|
* - sinks fetch via the injected {@link Downloader}; a result with no
|
|
@@ -117,6 +149,14 @@ export declare class RunResult {
|
|
|
117
149
|
readonly url?: string;
|
|
118
150
|
/** True iff {@link failed} is empty. */
|
|
119
151
|
readonly ok: boolean;
|
|
152
|
+
/**
|
|
153
|
+
* Whether any output missed its requested byte target. Derived from the
|
|
154
|
+
* per-output {@link OutputFile.targetSizeMet}: undefined when NO artifact
|
|
155
|
+
* reports a target-size outcome (every `targetSizeMet` undefined — not a
|
|
156
|
+
* target_size run); otherwise true iff some artifact has
|
|
157
|
+
* `targetSizeMet === false`.
|
|
158
|
+
*/
|
|
159
|
+
readonly targetSizeMissed?: boolean;
|
|
120
160
|
constructor(workflowId: string, state: string, artifacts: readonly OutputFile[], succeeded: readonly ItemResult[], failed: readonly ItemFailure[], downloader?: Downloader | undefined);
|
|
121
161
|
/**
|
|
122
162
|
* Address a succeeded input by the `key:` given to `file()`. Duplicate keys
|
|
@@ -143,16 +183,18 @@ export declare class RunResult {
|
|
|
143
183
|
failOnPartial?: boolean;
|
|
144
184
|
}): Promise<Manifest>;
|
|
145
185
|
/**
|
|
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
|
-
*
|
|
186
|
+
* Plain-object projection. Field ORDER (workflowId, state, ok,
|
|
187
|
+
* targetSizeMissed?, url?, artifacts, succeeded, failed) is fixed to match
|
|
188
|
+
* the PHP `toArray()` reference so JSON-string parity holds (FF1 shape
|
|
189
|
+
* assertion + FF2b harness fixture). `targetSizeMissed` + `url` are omitted
|
|
190
|
+
* entirely when undefined — `JSON.stringify` then produces the identical
|
|
191
|
+
* shape to PHP's omit-when-null `toArray()`.
|
|
151
192
|
*/
|
|
152
193
|
toJSON(): {
|
|
153
194
|
workflowId: string;
|
|
154
195
|
state: string;
|
|
155
196
|
ok: boolean;
|
|
197
|
+
targetSizeMissed?: boolean;
|
|
156
198
|
url?: string;
|
|
157
199
|
artifacts: readonly OutputFile[];
|
|
158
200
|
succeeded: readonly {
|
|
@@ -295,7 +337,7 @@ export declare const fileInput: {
|
|
|
295
337
|
};
|
|
296
338
|
/** One step in a {@link Recipe}'s chain — an op kind + captured ergonomic args. */
|
|
297
339
|
interface RecipeStep {
|
|
298
|
-
readonly opType: 'compress' | 'convert' | 'thumbnail' | 'text_watermark' | 'output';
|
|
340
|
+
readonly opType: 'compress' | 'convert' | 'thumbnail' | 'text_watermark' | 'output' | 'transform';
|
|
299
341
|
readonly options: Readonly<Record<string, unknown>>;
|
|
300
342
|
}
|
|
301
343
|
/**
|
|
@@ -349,6 +391,19 @@ export declare class Recipe {
|
|
|
349
391
|
* dropped from the wire options (not sent as `undefined`).
|
|
350
392
|
*/
|
|
351
393
|
thumbnail(options: ThumbnailOptions): Recipe;
|
|
394
|
+
/**
|
|
395
|
+
* Geometric transform: rotate (0/90/180/270°) and/or flip. Chainable — the
|
|
396
|
+
* canonical single-job order is `transform → convert → compress → thumbnail`,
|
|
397
|
+
* so downstream size options refer to the final (post-transform) frame.
|
|
398
|
+
*
|
|
399
|
+
* Passthrough: `rotate`/`flip` are forwarded as-is; the SDK does NOT narrow
|
|
400
|
+
* per media (a `flip` on a PDF input passes SDK validation but the server
|
|
401
|
+
* rejects it — documents rotate only). The transform op is `availability:
|
|
402
|
+
* planned` today, so workflow-create returns `feature_not_available` (422)
|
|
403
|
+
* until the per-media Lambdas ship. A no-op (`rotate:0` + `flip:none`) is
|
|
404
|
+
* rejected server-side as `invalid_options`.
|
|
405
|
+
*/
|
|
406
|
+
transform(options?: TransformOptions): Recipe;
|
|
352
407
|
/**
|
|
353
408
|
* Produce ONE transformed image: keep or change format, plus quality, resize
|
|
354
409
|
* and route-honored controls. The single user-facing image transform — the SDK
|
|
@@ -385,7 +440,8 @@ export declare class Recipe {
|
|
|
385
440
|
* (beta). Audio/document/animated-GIF/unsupported-subtype/undetectable bases
|
|
386
441
|
* throw locally BEFORE any upload (the planned-op gate). `options` carries the
|
|
387
442
|
* wire watermark options (`anchor`, `opacity`, `margin_x`, `margin_y`,
|
|
388
|
-
* `overlay_width`). Returns a
|
|
443
|
+
* `overlay_width`, or `overlays[]` for the multi-overlay stack). Returns a
|
|
444
|
+
* {@link WatermarkedRecipe} (chain post-watermark
|
|
389
445
|
* `compress`/`convert`/`thumbnail`, then `run`/`submit`). Distinct from
|
|
390
446
|
* {@link textWatermark} (single-input text overlay).
|
|
391
447
|
*/
|
|
@@ -437,6 +493,8 @@ export declare class Recipe {
|
|
|
437
493
|
maxWait?: string | number;
|
|
438
494
|
onProgress?: (event: ProgressEvent) => void;
|
|
439
495
|
signal?: AbortSignal;
|
|
496
|
+
/** Force the poll fallback instead of attempting SSE. Default true (SSE-first, poll fallback). */
|
|
497
|
+
useSSE?: boolean;
|
|
440
498
|
pollIntervalMs?: number;
|
|
441
499
|
probeBeforeCreate?: boolean;
|
|
442
500
|
probeTimeoutMs?: number;
|
|
@@ -536,6 +594,14 @@ export declare const WATERMARK_CAPABILITY: {
|
|
|
536
594
|
readonly mimes: readonly ["image/gif"];
|
|
537
595
|
readonly availability: "planned";
|
|
538
596
|
};
|
|
597
|
+
readonly image_tiff: {
|
|
598
|
+
readonly mimes: readonly ["image/tiff"];
|
|
599
|
+
readonly availability: "stable";
|
|
600
|
+
};
|
|
601
|
+
readonly image_bmp: {
|
|
602
|
+
readonly mimes: readonly ["image/bmp"];
|
|
603
|
+
readonly availability: "stable";
|
|
604
|
+
};
|
|
539
605
|
};
|
|
540
606
|
readonly video_watermark: {
|
|
541
607
|
readonly video: {
|
|
@@ -588,6 +654,8 @@ export declare class FilesRecipe {
|
|
|
588
654
|
convert(format: string, options?: ConvertOptions): FilesRecipe;
|
|
589
655
|
/** Generate a preview of every input. `width` AND `height` are required; validated via the base {@link Recipe} before any upload. */
|
|
590
656
|
thumbnail(options: ThumbnailOptions): FilesRecipe;
|
|
657
|
+
/** Apply the same geometric transform (rotate/flip) to every input. Validated via the base {@link Recipe}. */
|
|
658
|
+
transform(options?: TransformOptions): FilesRecipe;
|
|
591
659
|
/** Apply the same text watermark to every input. Option keys validated via the base {@link Recipe}. */
|
|
592
660
|
textWatermark(text: string, options?: TextWatermarkOptions): FilesRecipe;
|
|
593
661
|
/**
|
|
@@ -644,6 +712,8 @@ export declare class FilesRecipe {
|
|
|
644
712
|
maxWait?: string | number;
|
|
645
713
|
onProgress?: (event: ProgressEvent) => void;
|
|
646
714
|
signal?: AbortSignal;
|
|
715
|
+
/** Force the poll fallback instead of attempting SSE. Default true (SSE-first, poll fallback). */
|
|
716
|
+
useSSE?: boolean;
|
|
647
717
|
pollIntervalMs?: number;
|
|
648
718
|
probeBeforeCreate?: boolean;
|
|
649
719
|
probeTimeoutMs?: number;
|
|
@@ -724,6 +794,8 @@ export declare class MergedRecipe {
|
|
|
724
794
|
convert(format: string, options?: ConvertOptions): MergedRecipe;
|
|
725
795
|
/** Thumbnail the merged output. `width` AND `height` are required; validated pre-upload. */
|
|
726
796
|
thumbnail(options: ThumbnailOptions): MergedRecipe;
|
|
797
|
+
/** Geometric transform (rotate/flip) of the merged output. Passthrough; see {@link Recipe.transform}. */
|
|
798
|
+
transform(options?: TransformOptions): MergedRecipe;
|
|
727
799
|
/**
|
|
728
800
|
* Lower to the merge DAG: one `passthrough` source job per input + one
|
|
729
801
|
* `merge` job whose `operations[]` is `[merge, ...post-combine ops]`. The
|
|
@@ -751,6 +823,8 @@ export declare class MergedRecipe {
|
|
|
751
823
|
maxWait?: string | number;
|
|
752
824
|
onProgress?: (event: ProgressEvent) => void;
|
|
753
825
|
signal?: AbortSignal;
|
|
826
|
+
/** Force the poll fallback instead of attempting SSE. Default true (SSE-first, poll fallback). */
|
|
827
|
+
useSSE?: boolean;
|
|
754
828
|
pollIntervalMs?: number;
|
|
755
829
|
probeBeforeCreate?: boolean;
|
|
756
830
|
probeTimeoutMs?: number;
|
|
@@ -850,6 +924,8 @@ export declare class ArchivedRecipe {
|
|
|
850
924
|
maxWait?: string | number;
|
|
851
925
|
onProgress?: (event: ProgressEvent) => void;
|
|
852
926
|
signal?: AbortSignal;
|
|
927
|
+
/** Force the poll fallback instead of attempting SSE. Default true (SSE-first, poll fallback). */
|
|
928
|
+
useSSE?: boolean;
|
|
853
929
|
pollIntervalMs?: number;
|
|
854
930
|
probeBeforeCreate?: boolean;
|
|
855
931
|
probeTimeoutMs?: number;
|
|
@@ -907,6 +983,8 @@ export declare class WatermarkedRecipe {
|
|
|
907
983
|
convert(format: string, options?: ConvertOptions): WatermarkedRecipe;
|
|
908
984
|
/** Thumbnail the watermarked output. `width` AND `height` are required; validated pre-upload. */
|
|
909
985
|
thumbnail(options: ThumbnailOptions): WatermarkedRecipe;
|
|
986
|
+
/** Geometric transform (rotate/flip) of the watermarked output. Passthrough; see {@link Recipe.transform}. */
|
|
987
|
+
transform(options?: TransformOptions): WatermarkedRecipe;
|
|
910
988
|
/**
|
|
911
989
|
* Lower to the watermark DAG: a `src_0` passthrough/base-steps job + a `src_1`
|
|
912
990
|
* passthrough/overlay-steps job + one `watermark` job whose `inputs[]` consume
|
|
@@ -930,6 +1008,8 @@ export declare class WatermarkedRecipe {
|
|
|
930
1008
|
maxWait?: string | number;
|
|
931
1009
|
onProgress?: (event: ProgressEvent) => void;
|
|
932
1010
|
signal?: AbortSignal;
|
|
1011
|
+
/** Force the poll fallback instead of attempting SSE. Default true (SSE-first, poll fallback). */
|
|
1012
|
+
useSSE?: boolean;
|
|
933
1013
|
pollIntervalMs?: number;
|
|
934
1014
|
probeBeforeCreate?: boolean;
|
|
935
1015
|
probeTimeoutMs?: number;
|
|
@@ -968,4 +1048,111 @@ export declare class WatermarkedRecipe {
|
|
|
968
1048
|
private lowerPostSteps;
|
|
969
1049
|
private withStep;
|
|
970
1050
|
}
|
|
1051
|
+
/**
|
|
1052
|
+
* The keyed multi-recipe batch builder (FF7 / MFaCjL8d). `client.batch([r1, r2, …])`
|
|
1053
|
+
* runs N DISTINCT single-input keyed {@link Recipe}s as ONE workflow; the
|
|
1054
|
+
* partitioned {@link RunResult} addresses each entry's outputs by the caller key
|
|
1055
|
+
* given at `client.file(input, key)` time (`res.byKey('hero')`), and one failed
|
|
1056
|
+
* entry lands in `failed` without sinking the rest.
|
|
1057
|
+
*
|
|
1058
|
+
* **v1 scope (locked):** `.run()` only (no `submit()` / reattach — a follow-up);
|
|
1059
|
+
* single-input {@link Recipe} entries only — the multi-input builders
|
|
1060
|
+
* ({@link FilesRecipe}, {@link MergedRecipe}, {@link WatermarkedRecipe},
|
|
1061
|
+
* {@link ArchivedRecipe}) are REJECTED pre-upload. Cross-entry upload dedupe
|
|
1062
|
+
* IS applied (1LwSJcz1): two entries sourcing the SAME input (by
|
|
1063
|
+
* {@link inputIdentity}) upload ONCE and share the resulting fileId —
|
|
1064
|
+
* correctness-neutral (same bytes → same per-job output), it only elides
|
|
1065
|
+
* redundant uploads. Observable caveat: `onProgress` upload-phase events drop
|
|
1066
|
+
* to one-per-UNIQUE input rather than one-per-entry.
|
|
1067
|
+
*
|
|
1068
|
+
* **Lowering (one workflow):** for each entry `i`, lower its single job via
|
|
1069
|
+
* {@link Recipe.toWorkflowPayload} and re-id it `b{i}` — a POSITIONAL namespace
|
|
1070
|
+
* DISTINCT from the fan-out `file-{i}` / merge-archive-watermark `src_{i}` refs so
|
|
1071
|
+
* a future reattach can't misdetect the wire as a fan-out / merge. `keyByRef`
|
|
1072
|
+
* maps each `b{i}` ref to that entry's caller key, so
|
|
1073
|
+
* {@link projectMultiJobToRunResult} partitions per entry (1 job ↔ 1 key:
|
|
1074
|
+
* `completed` → `succeeded`, else → `failed` with a {@link GislItemFailedError}).
|
|
1075
|
+
*
|
|
1076
|
+
* **Immutability:** the ctor is CLIENT-ONLY (the ordered entries + the client) —
|
|
1077
|
+
* entries are already-built Recipes that captured their own preset defaults at
|
|
1078
|
+
* `client.file(...)` time, so batch never re-plumbs
|
|
1079
|
+
* presetDefaults/scopedPresetDefaults. Mirrors the PHP `BatchRecipe`.
|
|
1080
|
+
*/
|
|
1081
|
+
export declare class BatchRecipe {
|
|
1082
|
+
private readonly client?;
|
|
1083
|
+
private readonly recipes;
|
|
1084
|
+
constructor(recipes: ReadonlyArray<Recipe>, client?: GislClient | undefined);
|
|
1085
|
+
/**
|
|
1086
|
+
* Execute the batch end-to-end: validate + lowering-preflight EVERY entry
|
|
1087
|
+
* BEFORE any upload, upload each entry's input, create ONE multi-job workflow
|
|
1088
|
+
* (one `b{i}` job per entry), await a terminal state (SSE with poll fallback,
|
|
1089
|
+
* honouring `useSSE`), then partition the per-job downloads into a keyed
|
|
1090
|
+
* {@link RunResult}. `partially_failed` is a NORMAL terminal state here — the
|
|
1091
|
+
* completed entries land in `succeeded`, the rest in `failed`.
|
|
1092
|
+
*
|
|
1093
|
+
* Requires a client bound at construction time — `gisl().batch([...])` wires
|
|
1094
|
+
* it; a directly-constructed {@link BatchRecipe} (e.g. a lowering-only test)
|
|
1095
|
+
* throws {@link GislConfigError}. Mirrors the fan-out {@link FilesRecipe.run}.
|
|
1096
|
+
*/
|
|
1097
|
+
run(options?: {
|
|
1098
|
+
maxWait?: string | number;
|
|
1099
|
+
onProgress?: (event: ProgressEvent) => void;
|
|
1100
|
+
signal?: AbortSignal;
|
|
1101
|
+
/** Force the poll fallback instead of attempting SSE. Default true (SSE-first, poll fallback). */
|
|
1102
|
+
useSSE?: boolean;
|
|
1103
|
+
pollIntervalMs?: number;
|
|
1104
|
+
probeBeforeCreate?: boolean;
|
|
1105
|
+
probeTimeoutMs?: number;
|
|
1106
|
+
}): Promise<RunResult>;
|
|
1107
|
+
/**
|
|
1108
|
+
* Lower the batch to ONE multi-job workflow-create payload against a list of
|
|
1109
|
+
* resolved upload ids (one per entry, in entry order). Each entry `i` becomes
|
|
1110
|
+
* ONE job re-id'd `b{i}` carrying that entry's lowered `source` + `operations`.
|
|
1111
|
+
* Composes the single-file {@link Recipe.toWorkflowPayload} per entry so each
|
|
1112
|
+
* keeps its own media-hint + preset resolution and lowering logic is not
|
|
1113
|
+
* duplicated. `callback_url` is built in ONLY when a webhook is supplied
|
|
1114
|
+
* (batch v1 run() supplies none, so it is omitted).
|
|
1115
|
+
*
|
|
1116
|
+
* @internal Consumed by {@link run} (after uploading) and the cross-language
|
|
1117
|
+
* golden-payload lowering test (with fixed ids). Not caller-facing.
|
|
1118
|
+
*/
|
|
1119
|
+
toWorkflowPayload(fileIds: readonly string[], callbackUrl?: string): WorkflowCreatePayload;
|
|
1120
|
+
/** The number of recipe entries in this batch (introspection / tests). */
|
|
1121
|
+
get recipeCount(): number;
|
|
1122
|
+
/**
|
|
1123
|
+
* Validate the batch AND lowering-preflight every entry BEFORE any upload
|
|
1124
|
+
* fires — an invalid entry costs no bandwidth. TWO PASSES (mirrors PHP
|
|
1125
|
+
* `BatchRecipe`'s structural-loop-then-preflight-loop), throwing
|
|
1126
|
+
* {@link GislConfigError}:
|
|
1127
|
+
* 0. empty batch → `no_recipes` (checked first).
|
|
1128
|
+
* PASS 1 (structural, ALL entries in order):
|
|
1129
|
+
* - a KNOWN multi-input builder (checked FIRST — they do NOT extend
|
|
1130
|
+
* {@link Recipe}, so the not-a-Recipe catch-all would otherwise misreport
|
|
1131
|
+
* them as plain type errors) → `multi_input_recipe_unsupported`;
|
|
1132
|
+
* - a non-{@link Recipe} entry → `invalid_recipe`;
|
|
1133
|
+
* - a missing/empty key → `missing_key`;
|
|
1134
|
+
* - a duplicate key → `duplicate_key`.
|
|
1135
|
+
* PASS 2 (lowering preflight, ALL entries): lower each entry (via
|
|
1136
|
+
* {@link Recipe.toWorkflowPayload}) so an invalid lowering throws BEFORE any
|
|
1137
|
+
* upload, mirroring what {@link FilesRecipe} lowers pre-create.
|
|
1138
|
+
*
|
|
1139
|
+
* Two passes so a batch with MULTIPLE distinct violations throws the SAME
|
|
1140
|
+
* reason regardless of entry order (a structural error anywhere wins over a
|
|
1141
|
+
* lowering error elsewhere) — converging TS + PHP error reporting. The
|
|
1142
|
+
* offending key/index rides the MESSAGE (not `conflictingFields`, which is
|
|
1143
|
+
* reserved for wire FIELD names).
|
|
1144
|
+
*/
|
|
1145
|
+
private validatePreUpload;
|
|
1146
|
+
/**
|
|
1147
|
+
* Collapse the entry inputs to a first-appearance-unique list for cross-entry
|
|
1148
|
+
* upload dedupe: two entries sourcing the SAME input (by {@link inputIdentity})
|
|
1149
|
+
* upload ONCE and share the fileId. Returns the ordered `uniqueInputs` plus an
|
|
1150
|
+
* `entryToUnique` index map (length N, entry order) so {@link run} can expand
|
|
1151
|
+
* the unique fileIds back to one-per-entry before {@link toWorkflowPayload} —
|
|
1152
|
+
* keeping the b{i} refs + {@link keyByRef} N-length and correctness-neutral.
|
|
1153
|
+
*/
|
|
1154
|
+
private planUploads;
|
|
1155
|
+
/** Map each `b{i}` job ref to that entry's caller key (validated non-empty). */
|
|
1156
|
+
private keyByRef;
|
|
1157
|
+
}
|
|
971
1158
|
export {};
|