@giveitsmaller/sdk 0.6.0 → 0.8.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/dist/_audit.js +71 -0
- package/dist/builder.d.ts +406 -0
- package/dist/builder.js +706 -0
- package/dist/client.d.ts +10 -0
- package/dist/client.js +42 -6
- package/dist/credentials.d.ts +61 -0
- package/dist/credentials.js +200 -0
- package/dist/ergonomic/preset_resolver.d.ts +75 -0
- package/dist/ergonomic/preset_resolver.js +568 -0
- package/dist/ergonomic/presets/_translate.d.ts +11 -0
- package/dist/ergonomic/presets/_translate.js +35 -0
- package/dist/ergonomic/presets/audio_compress.d.ts +16 -0
- package/dist/ergonomic/presets/audio_compress.js +45 -0
- package/dist/ergonomic/presets/document_epub_compress.d.ts +14 -0
- package/dist/ergonomic/presets/document_epub_compress.js +34 -0
- package/dist/ergonomic/presets/document_odf_compress.d.ts +14 -0
- package/dist/ergonomic/presets/document_odf_compress.js +34 -0
- package/dist/ergonomic/presets/document_office_compress.d.ts +16 -0
- package/dist/ergonomic/presets/document_office_compress.js +40 -0
- package/dist/ergonomic/presets/document_pdf_compress.d.ts +14 -0
- package/dist/ergonomic/presets/document_pdf_compress.js +35 -0
- package/dist/ergonomic/presets/image_compress.d.ts +43 -0
- package/dist/ergonomic/presets/image_compress.js +95 -0
- package/dist/ergonomic/presets/index.d.ts +77 -0
- package/dist/ergonomic/presets/index.js +216 -0
- package/dist/ergonomic/presets/video_compress.d.ts +30 -0
- package/dist/ergonomic/presets/video_compress.js +83 -0
- package/dist/errors.d.ts +196 -1
- package/dist/errors.js +216 -0
- package/dist/file-first.d.ts +284 -0
- package/dist/file-first.js +445 -0
- package/dist/generated/sdk_spec/enums.d.ts +195 -0
- package/dist/generated/sdk_spec/enums.js +127 -0
- package/dist/generated/sdk_spec/errors.d.ts +16 -0
- package/dist/generated/sdk_spec/errors.js +523 -0
- package/dist/generated/sdk_spec/index.d.ts +4 -0
- package/dist/generated/sdk_spec/index.js +7 -0
- package/dist/generated/sdk_spec/presets.d.ts +6 -0
- package/dist/generated/sdk_spec/presets.js +157 -0
- package/dist/generated/sdk_spec/version.d.ts +3 -0
- package/dist/generated/sdk_spec/version.js +6 -0
- package/dist/gisl.d.ts +122 -0
- package/dist/gisl.js +283 -0
- package/dist/http-downloader.d.ts +9 -0
- package/dist/http-downloader.js +55 -0
- package/dist/index.d.ts +20 -5
- package/dist/index.js +45 -4
- package/dist/merge.d.ts +142 -0
- package/dist/merge.js +411 -0
- package/dist/types.d.ts +12 -14
- package/dist/types.js +18 -0
- package/package.json +3 -3
package/dist/errors.js
CHANGED
|
@@ -67,6 +67,39 @@ export class GislFeatureNotAvailableError extends GislApiError {
|
|
|
67
67
|
this.name = 'GislFeatureNotAvailableError';
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* 422 response on `POST /api/workflows` when a job references an upload
|
|
72
|
+
* whose server-side probe hasn't completed at workflow-create time. The
|
|
73
|
+
* server rejects rather than silently routing as `short_form` (which
|
|
74
|
+
* hard-fails long video clips).
|
|
75
|
+
*
|
|
76
|
+
* **Recovery contract** (per contracts ProbePendingResponse docblock):
|
|
77
|
+
* poll `POST /api/uploads/{id}/probe` for the pending upload until
|
|
78
|
+
* `probe_status` is terminal (`ok` → re-`POST /api/workflows` the same
|
|
79
|
+
* request; `corrupt` / `unsupported_codec` → surface the probe error).
|
|
80
|
+
* The `Retry-After` response header (when present) suggests a delay
|
|
81
|
+
* in seconds before the next poll/retry.
|
|
82
|
+
*
|
|
83
|
+
* `payload.jobRef` identifies which job in the multi-job request triggered
|
|
84
|
+
* the probe-pending rejection.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* try {
|
|
88
|
+
* await client.createWorkflow({ jobs });
|
|
89
|
+
* } catch (e) {
|
|
90
|
+
* if (e instanceof GislProbePendingError) {
|
|
91
|
+
* await waitForProbe(e.payload.jobRef);
|
|
92
|
+
* // retry...
|
|
93
|
+
* }
|
|
94
|
+
* throw e;
|
|
95
|
+
* }
|
|
96
|
+
*/
|
|
97
|
+
export class GislProbePendingError extends GislApiError {
|
|
98
|
+
constructor(statusCode, errorMessage, payload, path, extra) {
|
|
99
|
+
super(statusCode, errorMessage, path, undefined, buildOptionsWithPayload(payload, extra));
|
|
100
|
+
this.name = 'GislProbePendingError';
|
|
101
|
+
}
|
|
102
|
+
}
|
|
70
103
|
export class GislWorkflowExpiredError extends GislApiError {
|
|
71
104
|
constructor(statusCode, errorMessage, payload, path, extra) {
|
|
72
105
|
super(statusCode, errorMessage, path, undefined, buildOptionsWithPayload(payload, extra));
|
|
@@ -153,12 +186,155 @@ export class GislMultipartSessionAuthRequiredError extends GislApiError {
|
|
|
153
186
|
this.name = 'GislMultipartSessionAuthRequiredError';
|
|
154
187
|
}
|
|
155
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* Root of the LOCAL config-error tree — thrown before any HTTP/file I/O.
|
|
191
|
+
* Sibling of `GislApiError` (which represents server-side error envelopes).
|
|
192
|
+
* Reserve for fail-early errors raised by the ergonomic-layer factory or
|
|
193
|
+
* credential-chain resolver when the caller hasn't supplied something the
|
|
194
|
+
* SDK needs to make a request. Never carries an HTTP status code.
|
|
195
|
+
*
|
|
196
|
+
* Optional `metadata` (T4b — `27rE1fZn`) carries structured fields used
|
|
197
|
+
* by the preset resolver and other ergonomic-layer validators. Existing
|
|
198
|
+
* call sites that pass `(message)` keep working — metadata is purely
|
|
199
|
+
* additive and defaults to `undefined`.
|
|
200
|
+
*/
|
|
201
|
+
export class GislConfigError extends GislError {
|
|
202
|
+
reason;
|
|
203
|
+
conflictingFields;
|
|
204
|
+
resolvedSnapshot;
|
|
205
|
+
suggestion;
|
|
206
|
+
constructor(message, metadata) {
|
|
207
|
+
super(message);
|
|
208
|
+
this.name = 'GislConfigError';
|
|
209
|
+
if (metadata !== undefined) {
|
|
210
|
+
if (metadata.reason !== undefined)
|
|
211
|
+
this.reason = metadata.reason;
|
|
212
|
+
if (metadata.conflictingFields !== undefined) {
|
|
213
|
+
this.conflictingFields = metadata.conflictingFields;
|
|
214
|
+
}
|
|
215
|
+
if (metadata.resolvedSnapshot !== undefined) {
|
|
216
|
+
this.resolvedSnapshot = metadata.resolvedSnapshot;
|
|
217
|
+
}
|
|
218
|
+
if (metadata.suggestion !== undefined)
|
|
219
|
+
this.suggestion = metadata.suggestion;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* The ergonomic-layer factory `gisl.create()` could not resolve an API key
|
|
225
|
+
* from any of explicit arg, `GISL_API_KEY` env, or shared-config profile,
|
|
226
|
+
* AND the caller did not opt into anonymous or cookie-mode. Thrown BEFORE
|
|
227
|
+
* any file read or HTTP request — calls to `client.compress(...)`, `.run()`,
|
|
228
|
+
* etc., synchronously fail with this error.
|
|
229
|
+
*/
|
|
230
|
+
export class GislMissingCredentialsError extends GislConfigError {
|
|
231
|
+
constructor(message) {
|
|
232
|
+
super(message);
|
|
233
|
+
this.name = 'GislMissingCredentialsError';
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* The caller used `gisl.anonymous()` and then invoked an operation that is
|
|
238
|
+
* not in the anonymous-capable allowlist. Local-only — thrown before any I/O.
|
|
239
|
+
* Distinct from server-side `GislAuthError` (401/403 on the wire).
|
|
240
|
+
*/
|
|
241
|
+
export class GislFeatureRequiresAuthError extends GislConfigError {
|
|
242
|
+
operation;
|
|
243
|
+
constructor(operation, message) {
|
|
244
|
+
super(message);
|
|
245
|
+
this.name = 'GislFeatureRequiresAuthError';
|
|
246
|
+
this.operation = operation;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* `MergeBuilder.sequence(...)` referenced an asset that wasn't declared in
|
|
251
|
+
* the prior `client.merge(...)` call. Local validation runs BEFORE upload
|
|
252
|
+
* so the caller fails fast on the typo without burning bandwidth.
|
|
253
|
+
*/
|
|
254
|
+
export class GislUndeclaredAssetError extends GislConfigError {
|
|
255
|
+
assetId;
|
|
256
|
+
declaredAssets;
|
|
257
|
+
constructor(assetId, declaredAssets) {
|
|
258
|
+
super(`Sequence references asset '${assetId}' but it wasn't declared in merge(...). ` +
|
|
259
|
+
`Declared assets: [${declaredAssets.join(', ')}]. ` +
|
|
260
|
+
`Either pass it to merge(...) before sequencing, or remove the reference.`);
|
|
261
|
+
this.name = 'GislUndeclaredAssetError';
|
|
262
|
+
this.assetId = assetId;
|
|
263
|
+
this.declaredAssets = declaredAssets;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* `MergeBuilder.sequence(...)` was called but at least one declared asset
|
|
268
|
+
* wasn't referenced. Almost always a bug (wasted upload). Escape via
|
|
269
|
+
* `allowUnusedAssets: true` on the merge options.
|
|
270
|
+
*/
|
|
271
|
+
export class GislUnusedAssetError extends GislConfigError {
|
|
272
|
+
unusedAssets;
|
|
273
|
+
constructor(unusedAssets) {
|
|
274
|
+
super(`Assets [${unusedAssets.join(', ')}] were declared in merge(...) but never sequenced. ` +
|
|
275
|
+
`Reference them in .sequence(...), remove them from the declaration, ` +
|
|
276
|
+
`or pass {allowUnusedAssets: true} to opt out of this check.`);
|
|
277
|
+
this.name = 'GislUnusedAssetError';
|
|
278
|
+
this.unusedAssets = unusedAssets;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* `MergeBuilder.sequence(...)` on an image merge was given a `clip(ref, opts)`
|
|
283
|
+
* entry. Image merges have NO per-input options in the wire today — `transition`
|
|
284
|
+
* applies at the merge level and is uniform across all joins.
|
|
285
|
+
*/
|
|
286
|
+
export class GislPerInputOptionsNotSupportedError extends GislConfigError {
|
|
287
|
+
mediaKind;
|
|
288
|
+
constructor(mediaKind) {
|
|
289
|
+
super(`${mediaKind} merge has no per-input options today; set 'transition' at the ` +
|
|
290
|
+
`.merge(...) level instead — it applies to every join.`);
|
|
291
|
+
this.name = 'GislPerInputOptionsNotSupportedError';
|
|
292
|
+
this.mediaKind = mediaKind;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Thrown by future chain methods (`.compress()` / `.thumbnail()` /
|
|
297
|
+
* `.convert()` on an `OperationBuilder`) when the previous step produces
|
|
298
|
+
* MULTIPLE artifacts and the caller didn't explicitly call `.mapEach(...)`
|
|
299
|
+
* to opt into per-artifact fan-out. T6 ships the error class + the
|
|
300
|
+
* `.mapEach(...)` method; the chain methods themselves are a separate
|
|
301
|
+
* follow-up card, so this error is currently dormant — but the type +
|
|
302
|
+
* audit-gate registration land here so the future chain-method PR is a
|
|
303
|
+
* pure addition with no public-API churn.
|
|
304
|
+
*/
|
|
305
|
+
export class GislChainCardinalityMismatchError extends GislConfigError {
|
|
306
|
+
previousOperation;
|
|
307
|
+
attemptedOperation;
|
|
308
|
+
constructor(previousOperation, attemptedOperation) {
|
|
309
|
+
super(`Previous step (${previousOperation}) produces multiple artifacts; ` +
|
|
310
|
+
`use .mapEach(art => art.${attemptedOperation}(...)) to apply the chain per-artifact, ` +
|
|
311
|
+
`or branch to a single artifact first.`);
|
|
312
|
+
this.name = 'GislChainCardinalityMismatchError';
|
|
313
|
+
this.previousOperation = previousOperation;
|
|
314
|
+
this.attemptedOperation = attemptedOperation;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
156
317
|
export class GislTimeoutError extends GislError {
|
|
157
318
|
constructor(message) {
|
|
158
319
|
super(message);
|
|
159
320
|
this.name = 'GislTimeoutError';
|
|
160
321
|
}
|
|
161
322
|
}
|
|
323
|
+
/**
|
|
324
|
+
* Transport-level failure: the underlying `fetch` (or other transport) could
|
|
325
|
+
* not produce a usable response — DNS, TCP, TLS, a mid-stream disconnect, or a
|
|
326
|
+
* non-ok status / empty body when fetching a result download. Mirrors the PHP
|
|
327
|
+
* `Gisl\Sdk\Errors\GislNetworkError`. Subclasses `GislError` (not
|
|
328
|
+
* `GislApiError`) because it carries no contract error envelope. The concrete
|
|
329
|
+
* file-first {@link Downloader} raises this when the output URL cannot be read
|
|
330
|
+
* (a destination-WRITE failure is `GislSinkError` reason `write_failed`).
|
|
331
|
+
*/
|
|
332
|
+
export class GislNetworkError extends GislError {
|
|
333
|
+
constructor(message) {
|
|
334
|
+
super(message);
|
|
335
|
+
this.name = 'GislNetworkError';
|
|
336
|
+
}
|
|
337
|
+
}
|
|
162
338
|
export class GislAbortError extends GislError {
|
|
163
339
|
constructor(message) {
|
|
164
340
|
super(message);
|
|
@@ -198,3 +374,43 @@ export class GislMultipartPartCountError extends GislError {
|
|
|
198
374
|
this.maxParts = maxParts;
|
|
199
375
|
}
|
|
200
376
|
}
|
|
377
|
+
/**
|
|
378
|
+
* Thrown by the file-first `RunResult.byKey()` (FF1) when no result entry
|
|
379
|
+
* matches the requested key. A keyless run (no `key:` supplied to `file()`)
|
|
380
|
+
* is addressable positionally only — `byKey()` always throws.
|
|
381
|
+
*
|
|
382
|
+
* Mirrors the PHP `Gisl\Sdk\Errors\GislNoSuchKeyError`.
|
|
383
|
+
*/
|
|
384
|
+
export class GislNoSuchKeyError extends GislError {
|
|
385
|
+
constructor(message) {
|
|
386
|
+
super(message);
|
|
387
|
+
this.name = 'GislNoSuchKeyError';
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Thrown by the file-first `RunResult` sinks (`toFile()` / `downloadTo()`,
|
|
392
|
+
* FF1) when they cannot deliver. The machine-readable `reason` discriminates
|
|
393
|
+
* the three cases, mirroring the `reason`-bag convention on
|
|
394
|
+
* {@link GislConfigError}:
|
|
395
|
+
*
|
|
396
|
+
* - `not_single_output` — `toFile()` requires exactly one output but the
|
|
397
|
+
* run produced zero or more than one.
|
|
398
|
+
* - `downloader_unavailable` — the `RunResult` has no downloader bound (e.g. a
|
|
399
|
+
* browser / no-I/O context).
|
|
400
|
+
* - `partial_failure` — `downloadTo({ failOnPartial: true })` and the
|
|
401
|
+
* run had at least one failed input.
|
|
402
|
+
* - `duplicate_filename` — two outputs share a destination filename in one
|
|
403
|
+
* `downloadTo(dir)`, which would silently overwrite.
|
|
404
|
+
* - `write_failed` — a concrete {@link Downloader} could not open or
|
|
405
|
+
* stream to the destination path.
|
|
406
|
+
*
|
|
407
|
+
* Mirrors the PHP `Gisl\Sdk\Errors\GislSinkError`.
|
|
408
|
+
*/
|
|
409
|
+
export class GislSinkError extends GislError {
|
|
410
|
+
reason;
|
|
411
|
+
constructor(message, options) {
|
|
412
|
+
super(message);
|
|
413
|
+
this.name = 'GislSinkError';
|
|
414
|
+
this.reason = options.reason;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-first result surface — the value the file-first layer's `run()` /
|
|
3
|
+
* `Handle.wait()` / `Handle.result()` return (producers land in FF2b/FF5).
|
|
4
|
+
*
|
|
5
|
+
* Coexists with the operation-first `Result`/`Artifact` (in `builder.ts`)
|
|
6
|
+
* until the operation-first layer is removed (FF6). The file-first shape is
|
|
7
|
+
* flatter and adds an always-present per-input partition (`succeeded` /
|
|
8
|
+
* `failed`) so one bad input in a multi-input run doesn't sink the rest.
|
|
9
|
+
*
|
|
10
|
+
* Mirrors `packages/php/src/FileFirst/*`.
|
|
11
|
+
*/
|
|
12
|
+
import { type ProgressEvent } from './builder.js';
|
|
13
|
+
import type { GislClient } from './client.js';
|
|
14
|
+
import { OptimizeFor } from './generated/sdk_spec/enums.js';
|
|
15
|
+
import type { PresetDefaults } from './ergonomic/presets/index.js';
|
|
16
|
+
import type { WorkflowCreatePayload } from './types.js';
|
|
17
|
+
/**
|
|
18
|
+
* Streams a single output URL to a local path. The seam between the
|
|
19
|
+
* file-first {@link RunResult} sinks and the SDK's HTTP/auth layer.
|
|
20
|
+
*
|
|
21
|
+
* FF1 defines ONLY this type — the concrete implementation (fetch +
|
|
22
|
+
* filesystem streamer) is wired by the producer tickets (`run()`/`submit()`,
|
|
23
|
+
* FF2b/FF5), which construct a `RunResult` with a real downloader bound to
|
|
24
|
+
* the client's auth context. Unit tests inject a small stub. A `RunResult`
|
|
25
|
+
* built WITHOUT a downloader (e.g. in a browser, or any no-I/O context)
|
|
26
|
+
* throws {@link GislSinkError} from its sinks rather than reaching for a
|
|
27
|
+
* global client.
|
|
28
|
+
*
|
|
29
|
+
* Mirrors the PHP `Downloader` interface.
|
|
30
|
+
*
|
|
31
|
+
* STREAMING CONTRACT: implementations MUST stream the URL body to
|
|
32
|
+
* `destPath` — they MUST NOT buffer the whole output in memory. The
|
|
33
|
+
* `Promise<void>` return exists precisely so no buffered-bytes value can
|
|
34
|
+
* leak into the calling convention.
|
|
35
|
+
*/
|
|
36
|
+
export interface Downloader {
|
|
37
|
+
/**
|
|
38
|
+
* Stream the body at `url` to the local filesystem path `destPath`.
|
|
39
|
+
* Implementations create/overwrite `destPath`. Failures reject.
|
|
40
|
+
*/
|
|
41
|
+
downloadTo(url: string, destPath: string): Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A single deliverable output of a file-first run — the file-first layer's
|
|
45
|
+
* flat output type. Leaner than the operation-first `Artifact`: just the
|
|
46
|
+
* four fields a caller needs to identify + fetch an output.
|
|
47
|
+
*
|
|
48
|
+
* Mirrors the PHP `OutputFile`.
|
|
49
|
+
*/
|
|
50
|
+
export interface OutputFile {
|
|
51
|
+
readonly url: string;
|
|
52
|
+
readonly filename: string;
|
|
53
|
+
readonly sizeBytes: number;
|
|
54
|
+
readonly operation: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* One succeeded entry in {@link RunResult.succeeded}: a single input's
|
|
58
|
+
* outputs, addressable by the `key:` the caller gave that file (null when
|
|
59
|
+
* no key was supplied). Mirrors the PHP `ItemResult`.
|
|
60
|
+
*/
|
|
61
|
+
export interface ItemResult {
|
|
62
|
+
readonly key: string | null;
|
|
63
|
+
readonly outputs: readonly OutputFile[];
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* One failed entry in {@link RunResult.failed}: an input that did not
|
|
67
|
+
* produce a deliverable, paired with the cause. One bad input does not sink
|
|
68
|
+
* the rest of a multi-input run. `error` is `unknown` (mirroring the PHP
|
|
69
|
+
* `\Throwable`) so the caller narrows with `instanceof`. Mirrors the PHP
|
|
70
|
+
* `ItemFailure`.
|
|
71
|
+
*/
|
|
72
|
+
export interface ItemFailure {
|
|
73
|
+
readonly key: string | null;
|
|
74
|
+
readonly error: unknown;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Return value of {@link RunResult.downloadTo} — the local paths written,
|
|
78
|
+
* in the SAME order as {@link RunResult.artifacts}. Mirrors the PHP
|
|
79
|
+
* `Manifest`.
|
|
80
|
+
*/
|
|
81
|
+
export interface Manifest {
|
|
82
|
+
readonly paths: readonly string[];
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Result of a file-first run. Coexists with the operation-first `Result`
|
|
86
|
+
* (in `builder.ts`) until FF6.
|
|
87
|
+
*
|
|
88
|
+
* Mirrors the PHP `RunResult` class. A class (not a bare interface) because
|
|
89
|
+
* it carries the `byKey()`/`toFile()`/`downloadTo()` behaviour; the data
|
|
90
|
+
* fields stay public + readonly so `toArray()` round-trips.
|
|
91
|
+
*
|
|
92
|
+
* Field notes:
|
|
93
|
+
* - `url`: single-output sugar — the lone artifact's URL when exactly one
|
|
94
|
+
* output exists, else undefined.
|
|
95
|
+
* - `ok`: true iff `failed` is empty. (A boolean — the partition lists are
|
|
96
|
+
* `succeeded`/`failed`; resolves the design doc's `ok` bool-vs-list
|
|
97
|
+
* contradiction.)
|
|
98
|
+
* - `state`: lifecycle state (`completed` | `failed` | ...). Named `state`,
|
|
99
|
+
* NOT `status`, matching the file-first `StatusSnapshot.state`.
|
|
100
|
+
* - sinks fetch via the injected {@link Downloader}; a result with no
|
|
101
|
+
* downloader throws {@link GislSinkError} (reason `downloader_unavailable`).
|
|
102
|
+
*/
|
|
103
|
+
export declare class RunResult {
|
|
104
|
+
readonly workflowId: string;
|
|
105
|
+
readonly state: string;
|
|
106
|
+
readonly artifacts: readonly OutputFile[];
|
|
107
|
+
readonly succeeded: readonly ItemResult[];
|
|
108
|
+
readonly failed: readonly ItemFailure[];
|
|
109
|
+
private readonly downloader?;
|
|
110
|
+
/** Single-output sugar: the lone artifact's URL, or undefined for 0 / >1. */
|
|
111
|
+
readonly url?: string;
|
|
112
|
+
/** True iff {@link failed} is empty. */
|
|
113
|
+
readonly ok: boolean;
|
|
114
|
+
constructor(workflowId: string, state: string, artifacts: readonly OutputFile[], succeeded: readonly ItemResult[], failed: readonly ItemFailure[], downloader?: Downloader | undefined);
|
|
115
|
+
/**
|
|
116
|
+
* Address a succeeded input by the `key:` given to `file()`. Duplicate keys
|
|
117
|
+
* are not valid input — the producer enforces key uniqueness (a later
|
|
118
|
+
* ticket); the first match is returned.
|
|
119
|
+
* @throws {GislNoSuchKeyError} when no succeeded entry has that key (a
|
|
120
|
+
* keyless run always throws — it is positionally addressable only).
|
|
121
|
+
*/
|
|
122
|
+
byKey(key: string): ItemResult;
|
|
123
|
+
/**
|
|
124
|
+
* Write the single output to `path`. Requires EXACTLY ONE artifact.
|
|
125
|
+
* @throws {GislSinkError} reason `not_single_output` for 0/>1 outputs;
|
|
126
|
+
* reason `downloader_unavailable` when no downloader is bound.
|
|
127
|
+
*/
|
|
128
|
+
toFile(path: string): Promise<void>;
|
|
129
|
+
/**
|
|
130
|
+
* Download every output into `dir` (filename per output), in output order.
|
|
131
|
+
* Returns the {@link Manifest} of local paths written.
|
|
132
|
+
* @throws {GislSinkError} reason `partial_failure` when `failOnPartial` and
|
|
133
|
+
* the run had failed inputs; reason `downloader_unavailable` when no
|
|
134
|
+
* downloader is bound.
|
|
135
|
+
*/
|
|
136
|
+
downloadTo(dir: string, options?: {
|
|
137
|
+
failOnPartial?: boolean;
|
|
138
|
+
}): Promise<Manifest>;
|
|
139
|
+
/**
|
|
140
|
+
* Plain-object projection. Field ORDER (workflowId, state, ok, url?,
|
|
141
|
+
* artifacts, succeeded, failed) is fixed to match the PHP `toArray()`
|
|
142
|
+
* reference so JSON-string parity holds (FF1 shape assertion + FF2b harness
|
|
143
|
+
* fixture). `url` is omitted entirely when undefined — `JSON.stringify`
|
|
144
|
+
* then produces the identical shape to PHP's omit-when-null `toArray()`.
|
|
145
|
+
*/
|
|
146
|
+
toJSON(): {
|
|
147
|
+
workflowId: string;
|
|
148
|
+
state: string;
|
|
149
|
+
ok: boolean;
|
|
150
|
+
url?: string;
|
|
151
|
+
artifacts: readonly OutputFile[];
|
|
152
|
+
succeeded: readonly {
|
|
153
|
+
key: string | null;
|
|
154
|
+
outputs: readonly OutputFile[];
|
|
155
|
+
}[];
|
|
156
|
+
failed: readonly {
|
|
157
|
+
key: string | null;
|
|
158
|
+
error: string;
|
|
159
|
+
}[];
|
|
160
|
+
};
|
|
161
|
+
private requireDownloader;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* The primary file a {@link Recipe} operates on — the "subject" of the
|
|
165
|
+
* file-first surface. A discriminated union over the ways a caller names an
|
|
166
|
+
* input:
|
|
167
|
+
*
|
|
168
|
+
* - `path` — a local filesystem path (Node; the common case).
|
|
169
|
+
* - `blob` — an in-memory `Blob`/`File` (browser, or Node 18+).
|
|
170
|
+
* - `uploadId` — a previously-uploaded `file_id` (reuse across recipes).
|
|
171
|
+
*
|
|
172
|
+
* FF2a does NO upload, so only the `path` + `uploadId` arms are exercised
|
|
173
|
+
* end-to-end here; the `blob` arm is DEFINED and type-checked but its upload
|
|
174
|
+
* is wired by FF2b (`run()`). Mirrors the PHP `FileInput` value object.
|
|
175
|
+
*/
|
|
176
|
+
export type FileInput = {
|
|
177
|
+
readonly kind: 'path';
|
|
178
|
+
readonly path: string;
|
|
179
|
+
} | {
|
|
180
|
+
readonly kind: 'blob';
|
|
181
|
+
readonly blob: Blob;
|
|
182
|
+
} | {
|
|
183
|
+
readonly kind: 'uploadId';
|
|
184
|
+
readonly fileId: string;
|
|
185
|
+
};
|
|
186
|
+
/** Named constructors for {@link FileInput} — mirror the PHP static factories. */
|
|
187
|
+
export declare const fileInput: {
|
|
188
|
+
readonly path: (path: string) => FileInput;
|
|
189
|
+
readonly blob: (blob: Blob) => FileInput;
|
|
190
|
+
readonly uploadId: (fileId: string) => FileInput;
|
|
191
|
+
};
|
|
192
|
+
/** One step in a {@link Recipe}'s chain — an op kind + captured ergonomic args. */
|
|
193
|
+
interface RecipeStep {
|
|
194
|
+
readonly opType: 'compress' | 'convert' | 'thumbnail' | 'text_watermark';
|
|
195
|
+
readonly options: Readonly<Record<string, unknown>>;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* The file-first builder value. `client.file(path)` returns a `Recipe`;
|
|
199
|
+
* single-input operations called on it (`compress`, `convert`, `thumbnail`,
|
|
200
|
+
* `textWatermark`) chain SEQUENTIALLY — each op feeds the next, and the chain
|
|
201
|
+
* lowers to ONE workflow job with an ordered `operations[]` (per ADR-0004:
|
|
202
|
+
* operations execute sequentially, each consuming the previous output). A
|
|
203
|
+
* chain yields the TERMINAL output only; intermediates are consumed (surfaced
|
|
204
|
+
* by FF2b's `run()`/{@link RunResult}).
|
|
205
|
+
*
|
|
206
|
+
* **Immutable / clone-on-write.** Every op returns a NEW `Recipe` carrying the
|
|
207
|
+
* appended step — `this` is never mutated. A Recipe is therefore a reusable
|
|
208
|
+
* value: branching the same base recipe two different ways cannot let one
|
|
209
|
+
* branch observe the other's steps (the aliasing trap mutable builders fall
|
|
210
|
+
* into).
|
|
211
|
+
*
|
|
212
|
+
* FF2a is network-free: there is NO `run()` here (that is FF2b). The lowering
|
|
213
|
+
* seam {@link toWorkflowPayload} takes the resolved upload id as a parameter
|
|
214
|
+
* so it stays pure — FF2b's `run()` calls the SAME method after uploading, and
|
|
215
|
+
* the parity harness calls it with a fixed id to assert the lowered shape.
|
|
216
|
+
*
|
|
217
|
+
* Mirrors the PHP `Recipe`.
|
|
218
|
+
*/
|
|
219
|
+
export declare class Recipe {
|
|
220
|
+
private readonly input;
|
|
221
|
+
private readonly recipeKey;
|
|
222
|
+
private readonly steps;
|
|
223
|
+
private readonly presetDefaults?;
|
|
224
|
+
private readonly scopedPresetDefaults?;
|
|
225
|
+
private readonly client?;
|
|
226
|
+
constructor(input: FileInput, recipeKey?: string | undefined, steps?: readonly RecipeStep[], presetDefaults?: PresetDefaults | undefined, scopedPresetDefaults?: PresetDefaults | undefined, client?: GislClient | undefined);
|
|
227
|
+
/**
|
|
228
|
+
* Reduce file size. `optimize` selects a per-media preset (resolved to
|
|
229
|
+
* concrete wire fields at lower-time, exactly as `client.compress()` does).
|
|
230
|
+
*/
|
|
231
|
+
compress(optimize?: OptimizeFor): Recipe;
|
|
232
|
+
/** Change format. `format` is lowered verbatim to the `format` wire option. */
|
|
233
|
+
convert(format: string): Recipe;
|
|
234
|
+
/**
|
|
235
|
+
* Generate a preview. Width and/or height in pixels; an omitted dimension is
|
|
236
|
+
* dropped from the wire options (not sent as `undefined`).
|
|
237
|
+
*/
|
|
238
|
+
thumbnail(options?: {
|
|
239
|
+
width?: number;
|
|
240
|
+
height?: number;
|
|
241
|
+
}): Recipe;
|
|
242
|
+
/**
|
|
243
|
+
* Apply a text watermark. Single-input (the text is an option, not a
|
|
244
|
+
* secondary file) — lowers to the `text_watermark` op with a `text` option.
|
|
245
|
+
*/
|
|
246
|
+
textWatermark(text: string): Recipe;
|
|
247
|
+
/**
|
|
248
|
+
* Lower this recipe to a workflow-create payload against a resolved upload
|
|
249
|
+
* id. Single-input chain → ONE job, `source: upload(fileId)`, ordered
|
|
250
|
+
* `operations[]`; the job `id` is omitted (a single job referenced by
|
|
251
|
+
* nothing — the server auto-assigns `job_N`).
|
|
252
|
+
*
|
|
253
|
+
* @internal Consumed by FF2b's `run()` (after a real upload) and by the
|
|
254
|
+
* cross-language parity harness (with a fixed id). Not part of the
|
|
255
|
+
* caller-facing fluent surface.
|
|
256
|
+
*/
|
|
257
|
+
toWorkflowPayload(fileId: string): WorkflowCreatePayload;
|
|
258
|
+
/** The result-addressing key passed to `file()`, or undefined. */
|
|
259
|
+
key(): string | undefined;
|
|
260
|
+
/** The number of operations chained so far (introspection / tests). */
|
|
261
|
+
get stepCount(): number;
|
|
262
|
+
/**
|
|
263
|
+
* Execute the recipe end-to-end: upload the input (when required), create
|
|
264
|
+
* the workflow, await a terminal state (SSE with poll fallback), then
|
|
265
|
+
* resolve the produced downloads into a flat {@link RunResult}. Throws
|
|
266
|
+
* {@link GislTimeoutError} if `maxWait` elapses before terminal status.
|
|
267
|
+
*
|
|
268
|
+
* Mirrors the operation-first `OperationBuilder.run` (in `builder.ts`).
|
|
269
|
+
* Requires a client bound at construction time — `gisl().file(...)` wires
|
|
270
|
+
* it; a directly-constructed `Recipe` (e.g. in a lowering-only test) has no
|
|
271
|
+
* client and throws {@link GislConfigError}.
|
|
272
|
+
*/
|
|
273
|
+
run(options?: {
|
|
274
|
+
maxWait?: string | number;
|
|
275
|
+
onProgress?: (event: ProgressEvent) => void;
|
|
276
|
+
signal?: AbortSignal;
|
|
277
|
+
pollIntervalMs?: number;
|
|
278
|
+
}): Promise<RunResult>;
|
|
279
|
+
private withStep;
|
|
280
|
+
private lowerStep;
|
|
281
|
+
private lowerCompressOptions;
|
|
282
|
+
private compressMediaHint;
|
|
283
|
+
}
|
|
284
|
+
export {};
|