@giveitsmaller/sdk 0.8.0 → 0.10.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 +8 -0
- package/dist/_audit.js +5 -1
- package/dist/builder.d.ts +1 -8
- package/dist/builder.js +72 -18
- package/dist/client.d.ts +38 -2
- package/dist/client.js +131 -7
- package/dist/credentials.js +4 -2
- package/dist/ergonomic/preset_resolver.js +4 -5
- package/dist/ergonomic/presets/image_compress.d.ts +1 -9
- package/dist/ergonomic/presets/image_compress.js +6 -25
- package/dist/ergonomic/presets/index.d.ts +1 -1
- package/dist/ergonomic/presets/index.js +1 -1
- package/dist/errors.d.ts +75 -1
- package/dist/errors.js +73 -0
- package/dist/file-first.d.ts +456 -4
- package/dist/file-first.js +1042 -83
- package/dist/generated/sdk_spec/enums.d.ts +0 -11
- package/dist/generated/sdk_spec/enums.js +0 -7
- package/dist/generated/sdk_spec/errors.d.ts +1 -1
- package/dist/generated/sdk_spec/errors.js +26 -0
- package/dist/generated/sdk_spec/presets.js +0 -3
- package/dist/generated/sdk_spec/version.d.ts +2 -2
- package/dist/generated/sdk_spec/version.js +2 -2
- package/dist/gisl.d.ts +22 -1
- package/dist/gisl.js +31 -1
- package/dist/handle.d.ts +153 -0
- package/dist/handle.js +273 -0
- package/dist/index.browser.d.ts +1 -0
- package/dist/index.browser.js +14 -0
- package/dist/index.core.d.ts +35 -0
- package/dist/index.core.js +102 -0
- package/dist/index.d.ts +1 -30
- package/dist/index.js +9 -73
- package/dist/lazy-downloader.d.ts +19 -0
- package/dist/lazy-downloader.js +19 -0
- package/dist/merge.d.ts +13 -1
- package/dist/merge.js +186 -55
- package/dist/node-fs.browser.d.ts +17 -0
- package/dist/node-fs.browser.js +7 -0
- package/dist/node-fs.d.ts +14 -0
- package/dist/node-fs.js +14 -0
- package/dist/sha256.d.ts +20 -0
- package/dist/sha256.js +108 -0
- package/dist/types.d.ts +54 -2
- package/dist/types.js +2 -0
- package/package.json +15 -2
package/dist/file-first.d.ts
CHANGED
|
@@ -11,9 +11,12 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { type ProgressEvent } from './builder.js';
|
|
13
13
|
import type { GislClient } from './client.js';
|
|
14
|
+
import type { OperationDownload, WorkflowStatusResponse } from '@giveitsmaller/contracts/openapi';
|
|
14
15
|
import { OptimizeFor } from './generated/sdk_spec/enums.js';
|
|
15
16
|
import type { PresetDefaults } from './ergonomic/presets/index.js';
|
|
16
17
|
import type { WorkflowCreatePayload } from './types.js';
|
|
18
|
+
import type { MergeOptions } from './merge.js';
|
|
19
|
+
import { Handle } from './handle.js';
|
|
17
20
|
/**
|
|
18
21
|
* Streams a single output URL to a local path. The seam between the
|
|
19
22
|
* file-first {@link RunResult} sinks and the SDK's HTTP/auth layer.
|
|
@@ -160,6 +163,92 @@ export declare class RunResult {
|
|
|
160
163
|
};
|
|
161
164
|
private requireDownloader;
|
|
162
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Flatten the terminal workflow status + its downloads into a {@link RunResult}.
|
|
168
|
+
*
|
|
169
|
+
* Shared by {@link Recipe.run} (passes its recipe key) and the file-first
|
|
170
|
+
* {@link Handle} reattach surface (`Handle.wait()`/`Handle.result()`, FF5a —
|
|
171
|
+
* passes `null` because a reattached handle carries no recipe key).
|
|
172
|
+
*
|
|
173
|
+
* **Partition invariant (carries a prior codex-review fix — do NOT let it
|
|
174
|
+
* drift):** success is ONLY `state === 'completed'`. Every other terminal
|
|
175
|
+
* state — `failed`, `partially_failed`, `cancelled`, `expired`,
|
|
176
|
+
* `paused_insufficient_credits` — partitions into `failed[]` so a caller's
|
|
177
|
+
* `ok`/`succeeded` check can never treat a cancelled/expired/paused run as a
|
|
178
|
+
* clean result.
|
|
179
|
+
*
|
|
180
|
+
* @internal Exported for reuse by the file-first `Handle`; not part of the
|
|
181
|
+
* caller-facing fluent surface.
|
|
182
|
+
*/
|
|
183
|
+
export declare function projectDownloadsToRunResult(workflowId: string, finalStatus: WorkflowStatusResponse, jobDownloads: readonly {
|
|
184
|
+
files: readonly OperationDownload[];
|
|
185
|
+
}[], key: string | null, downloader?: Downloader): RunResult;
|
|
186
|
+
/**
|
|
187
|
+
* Flatten a terminal multi-job workflow (the `client.files([...])` fan-out)
|
|
188
|
+
* into a partitioned {@link RunResult}. One job per input file, keyed by the
|
|
189
|
+
* `file-{i}` job ref the {@link FilesRecipe} lowering assigns; the result's
|
|
190
|
+
* `succeeded` / `failed` partition is PER JOB, so one bad input does not sink
|
|
191
|
+
* the rest.
|
|
192
|
+
*
|
|
193
|
+
* Join model: `finalStatus.jobs[]` carries the per-job {@link JobStatus} +
|
|
194
|
+
* `operations[]` (for the error message); `jobDownloads[]` carries the per-job
|
|
195
|
+
* output files. Both are joined on the job `ref` ("file-{i}"); the partition
|
|
196
|
+
* key is the index `"{i}"` parsed out of that ref. The flat `artifacts[]` is
|
|
197
|
+
* every job's outputs in job order (the order `finalStatus.jobs[]` lists them).
|
|
198
|
+
*
|
|
199
|
+
* **Partition invariant (mirrors {@link projectDownloadsToRunResult} PER JOB —
|
|
200
|
+
* do NOT let it drift):** a job is a SUCCESS only when its
|
|
201
|
+
* {@link JobResponse.status} `=== 'completed'`. Any other per-job status —
|
|
202
|
+
* `failed`, `pending`, `waiting`, `blocked_insufficient_credits`,
|
|
203
|
+
* `in_progress` — partitions that job into `failed[]` (with that job's first
|
|
204
|
+
* operation error message, scoped to THAT job only).
|
|
205
|
+
*
|
|
206
|
+
* @internal Exported for the file-first `client.files([...]).run()` producer;
|
|
207
|
+
* not part of the caller-facing fluent surface.
|
|
208
|
+
*/
|
|
209
|
+
export declare function projectMultiJobToRunResult(workflowId: string, finalStatus: WorkflowStatusResponse, jobDownloads: readonly {
|
|
210
|
+
ref: string;
|
|
211
|
+
files: readonly OperationDownload[];
|
|
212
|
+
}[], keyByRef: ReadonlyMap<string, string | null>, downloader?: Downloader): RunResult;
|
|
213
|
+
/**
|
|
214
|
+
* True when a terminal status describes a homogeneous `files([...])` fan-out —
|
|
215
|
+
* i.e. it has at least one job and EVERY job ref is `file-{i}` (the ids the
|
|
216
|
+
* {@link FilesRecipe} lowering assigns). A single-file {@link Recipe} omits the
|
|
217
|
+
* job id, so its job carries a non-`file-N` ref (e.g. `op`) and this is false.
|
|
218
|
+
*
|
|
219
|
+
* This is the data-driven seam that lets {@link Handle.wait}/{@link Handle.result}
|
|
220
|
+
* pick the per-job producer ({@link projectMultiJobToRunResult}) over the
|
|
221
|
+
* single-output one for a fan-out — WITHOUT a construction-time marker, so a
|
|
222
|
+
* fan-out **reattached** via `client.workflow(id)` (which carries no marker)
|
|
223
|
+
* still partitions per job. Keys are recovered from the `file-{i}` refs.
|
|
224
|
+
*
|
|
225
|
+
* @internal Exported for the file-first `Handle`; not part of the public API.
|
|
226
|
+
*/
|
|
227
|
+
export declare function isFanoutStatus(finalStatus: WorkflowStatusResponse): boolean;
|
|
228
|
+
/**
|
|
229
|
+
* True when a terminal status describes a fluent `files([...]).merge(...)`
|
|
230
|
+
* combine — at least one job ref `merge` and every OTHER job ref is `src_{i}`
|
|
231
|
+
* (the ids the {@link MergedRecipe} lowering assigns). The data-driven seam that
|
|
232
|
+
* lets {@link Handle.wait}/{@link Handle.result} project ONLY the merged output
|
|
233
|
+
* — filtering the `src_*` passthrough plumbing — even after a
|
|
234
|
+
* `client.workflow(id)` reattach (no construction-time marker), matching
|
|
235
|
+
* {@link MergedRecipe.run}'s `ref === 'merge'` filter. Mutually exclusive with
|
|
236
|
+
* {@link isFanoutStatus} (a fan-out's refs are all `file-{i}`).
|
|
237
|
+
*
|
|
238
|
+
* @internal Exported for the file-first `Handle`; not part of the public API.
|
|
239
|
+
*/
|
|
240
|
+
export declare function isMergeStatus(finalStatus: WorkflowStatusResponse): boolean;
|
|
241
|
+
/**
|
|
242
|
+
* True when a terminal status describes a fluent `files([...]).archive(...)`
|
|
243
|
+
* bundle — at least one job ref `archive` and every OTHER job ref is `src_{i}`
|
|
244
|
+
* (the ids the {@link ArchivedRecipe} lowering assigns). Lets
|
|
245
|
+
* {@link Handle.wait}/{@link Handle.result} project ONLY the archive output —
|
|
246
|
+
* filtering the `src_*` passthrough plumbing — even after a `client.workflow(id)`
|
|
247
|
+
* reattach. Mutually exclusive with {@link isFanoutStatus} / {@link isMergeStatus}.
|
|
248
|
+
*
|
|
249
|
+
* @internal Exported for the file-first `Handle`; not part of the public API.
|
|
250
|
+
*/
|
|
251
|
+
export declare function isArchiveStatus(finalStatus: WorkflowStatusResponse): boolean;
|
|
163
252
|
/**
|
|
164
253
|
* The primary file a {@link Recipe} operates on — the "subject" of the
|
|
165
254
|
* file-first surface. A discriminated union over the ways a caller names an
|
|
@@ -187,6 +276,19 @@ export type FileInput = {
|
|
|
187
276
|
export declare const fileInput: {
|
|
188
277
|
readonly path: (path: string) => FileInput;
|
|
189
278
|
readonly blob: (blob: Blob) => FileInput;
|
|
279
|
+
/**
|
|
280
|
+
* Reference an already-uploaded file by its upload id, instead of
|
|
281
|
+
* re-uploading bytes.
|
|
282
|
+
*
|
|
283
|
+
* Auth-ownership: an upload created by an **authenticated** caller is owned
|
|
284
|
+
* by that caller. If you reuse the id from a client configured with a
|
|
285
|
+
* *different* auth context (a different `apiKey` / session), workflow-create
|
|
286
|
+
* returns `404 upload_not_found` — the server enforces ownership (api
|
|
287
|
+
* PqpD9ySv). Reference an upload id only under the SAME auth that created it.
|
|
288
|
+
* The normal upload-then-create-in-one-client flow is consistent by
|
|
289
|
+
* construction (the same `Authorization` rides every request). Ownerless
|
|
290
|
+
* (anonymous-intake) uploads are unaffected.
|
|
291
|
+
*/
|
|
190
292
|
readonly uploadId: (fileId: string) => FileInput;
|
|
191
293
|
};
|
|
192
294
|
/** One step in a {@link Recipe}'s chain — an op kind + captured ergonomic args. */
|
|
@@ -250,15 +352,25 @@ export declare class Recipe {
|
|
|
250
352
|
* `operations[]`; the job `id` is omitted (a single job referenced by
|
|
251
353
|
* nothing — the server auto-assigns `job_N`).
|
|
252
354
|
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
255
|
-
*
|
|
355
|
+
* When `callbackUrl` is given (the file-first `submit()` path), it is built
|
|
356
|
+
* INTO the payload at construction (`callback_url`) rather than spread onto an
|
|
357
|
+
* already-built readonly payload. `run()` passes no `callbackUrl`.
|
|
358
|
+
*
|
|
359
|
+
* @internal Consumed by FF2b's `run()` (after a real upload), FF5b's
|
|
360
|
+
* `submit()` (with a webhook), and the cross-language parity harness (with a
|
|
361
|
+
* fixed id). Not part of the caller-facing fluent surface.
|
|
256
362
|
*/
|
|
257
|
-
toWorkflowPayload(fileId: string): WorkflowCreatePayload;
|
|
363
|
+
toWorkflowPayload(fileId: string, callbackUrl?: string): WorkflowCreatePayload;
|
|
258
364
|
/** The result-addressing key passed to `file()`, or undefined. */
|
|
259
365
|
key(): string | undefined;
|
|
260
366
|
/** The number of operations chained so far (introspection / tests). */
|
|
261
367
|
get stepCount(): number;
|
|
368
|
+
/**
|
|
369
|
+
* The captured op chain. Read by {@link FilesRecipe} to compose a shared
|
|
370
|
+
* chain across many inputs without duplicating the chain-method validation.
|
|
371
|
+
* @internal
|
|
372
|
+
*/
|
|
373
|
+
get recipeSteps(): readonly RecipeStep[];
|
|
262
374
|
/**
|
|
263
375
|
* Execute the recipe end-to-end: upload the input (when required), create
|
|
264
376
|
* the workflow, await a terminal state (SSE with poll fallback), then
|
|
@@ -276,9 +388,349 @@ export declare class Recipe {
|
|
|
276
388
|
signal?: AbortSignal;
|
|
277
389
|
pollIntervalMs?: number;
|
|
278
390
|
}): Promise<RunResult>;
|
|
391
|
+
/**
|
|
392
|
+
* Fire-and-forget the recipe: upload the input (when required), create the
|
|
393
|
+
* workflow (wiring `webhook` into `callback_url` when given), and return a
|
|
394
|
+
* client-bound {@link Handle} carrying the workflow id + webhook secret + the
|
|
395
|
+
* recipe key. Does NOT wait for terminal status — call `handle.wait()` /
|
|
396
|
+
* `handle.result()` later to collect the {@link RunResult}.
|
|
397
|
+
*
|
|
398
|
+
* Requires a client bound at construction time (same `no_client` guard as
|
|
399
|
+
* {@link run}). `webhook` is OPTIONAL: when omitted, no `callback_url` is
|
|
400
|
+
* sent. Mirrors the PHP `Recipe.submit()`.
|
|
401
|
+
*
|
|
402
|
+
* @param webhook Absolute callback URL the server POSTs lifecycle events to.
|
|
403
|
+
*/
|
|
404
|
+
submit(webhook?: string): Promise<Handle>;
|
|
405
|
+
/**
|
|
406
|
+
* Resolve the upload id (verbatim for a pre-uploaded id; uploading a path /
|
|
407
|
+
* blob otherwise, emitting `{phase:'upload'}` progress), check the post-upload
|
|
408
|
+
* deadline, lower to the workflow-create payload (wiring `webhook` into
|
|
409
|
+
* `callback_url`), and create the workflow. Shared first half of
|
|
410
|
+
* {@link run} + {@link submit}.
|
|
411
|
+
*
|
|
412
|
+
* The post-upload deadline check carries a prior codex fix (9a117f04eb59): a
|
|
413
|
+
* slow upload must not proceed to createWorkflow past the deadline.
|
|
414
|
+
*/
|
|
415
|
+
private _uploadAndCreate;
|
|
279
416
|
private withStep;
|
|
280
417
|
private lowerStep;
|
|
281
418
|
private lowerCompressOptions;
|
|
282
419
|
private compressMediaHint;
|
|
283
420
|
}
|
|
421
|
+
/**
|
|
422
|
+
* The homogeneous fan-out builder value (FF3a). `client.files([a, b, c])`
|
|
423
|
+
* returns a `FilesRecipe`; the op-chain methods (`compress`, `convert`,
|
|
424
|
+
* `thumbnail`, `textWatermark`) build ONE shared recipe (chain) that is applied
|
|
425
|
+
* to EVERY input file in ONE workflow. `run()` returns a partitioned
|
|
426
|
+
* {@link RunResult} — one `succeeded`/`failed` entry per input, keyed by its
|
|
427
|
+
* 0-based index ("0", "1", …) so one bad input does not sink the rest.
|
|
428
|
+
*
|
|
429
|
+
* **Immutable / clone-on-write**, exactly like {@link Recipe}: every op returns
|
|
430
|
+
* a NEW `FilesRecipe` carrying the appended step. The inputs are held as an
|
|
431
|
+
* ORDERED list (NOT a map) so the per-file index is the partition key.
|
|
432
|
+
*
|
|
433
|
+
* **Lowering composes {@link Recipe} per file** rather than duplicating
|
|
434
|
+
* `lowerStep`/`lowerCompressOptions`: for each input `i` it builds an internal
|
|
435
|
+
* single-file `Recipe(input_i, …, steps)`, calls its `toWorkflowPayload` to get
|
|
436
|
+
* that file's one-job payload, then merges all jobs into ONE
|
|
437
|
+
* {@link WorkflowCreatePayload} with `jobs[i].id = "file-{i}"`. This preserves
|
|
438
|
+
* each file's media-hint (different extensions per input resolve compress
|
|
439
|
+
* presets independently).
|
|
440
|
+
*
|
|
441
|
+
* Exposes both `run()` (blocking, returns a partitioned {@link RunResult}) and
|
|
442
|
+
* `submit(webhook?)` (fire-and-forget, returns a {@link Handle}). Mirrors the
|
|
443
|
+
* PHP `FilesRecipe`.
|
|
444
|
+
*/
|
|
445
|
+
export declare class FilesRecipe {
|
|
446
|
+
private readonly inputs;
|
|
447
|
+
private readonly steps;
|
|
448
|
+
private readonly presetDefaults?;
|
|
449
|
+
private readonly scopedPresetDefaults?;
|
|
450
|
+
private readonly client?;
|
|
451
|
+
constructor(inputs: readonly FileInput[], steps?: readonly RecipeStep[], presetDefaults?: PresetDefaults | undefined, scopedPresetDefaults?: PresetDefaults | undefined, client?: GislClient | undefined);
|
|
452
|
+
/**
|
|
453
|
+
* Reduce file size on every input. `optimize` selects a per-media preset
|
|
454
|
+
* (resolved per file at lower-time, so each input's extension picks its own
|
|
455
|
+
* preset). Reuses {@link Recipe}'s validation — a directly-constructed
|
|
456
|
+
* lowering builds an internal Recipe that throws the same `GislConfigError`.
|
|
457
|
+
*/
|
|
458
|
+
compress(optimize?: OptimizeFor): FilesRecipe;
|
|
459
|
+
/** Change every input's format. `format` lowers verbatim to the `format` option. */
|
|
460
|
+
convert(format: string): FilesRecipe;
|
|
461
|
+
/** Generate a preview of every input. Omitted dimensions are dropped from the wire options. */
|
|
462
|
+
thumbnail(options?: {
|
|
463
|
+
width?: number;
|
|
464
|
+
height?: number;
|
|
465
|
+
}): FilesRecipe;
|
|
466
|
+
/** Apply the same text watermark to every input. */
|
|
467
|
+
textWatermark(text: string): FilesRecipe;
|
|
468
|
+
/**
|
|
469
|
+
* Combine the inputs into ONE output (N→1), in array order (FF3b). Returns a
|
|
470
|
+
* single-output {@link MergedRecipe} you chain further ops on
|
|
471
|
+
* (`files([...]).merge().compress()`). Reuses the operation-first
|
|
472
|
+
* {@link MergeOptions} for the merge-level options, so the wire shape matches
|
|
473
|
+
* `client.merge([...], options)`.
|
|
474
|
+
*
|
|
475
|
+
* `merge()` must be the FIRST op on `files([...])` — per-file ops before a
|
|
476
|
+
* combine (compress-each-then-merge) are a separate follow-up, rejected here
|
|
477
|
+
* with `GislConfigError` reason `pre_merge_ops_unsupported`.
|
|
478
|
+
*/
|
|
479
|
+
merge(options?: MergeOptions): MergedRecipe;
|
|
480
|
+
/**
|
|
481
|
+
* Bundle the inputs into ONE archive (N→1, zip / tar.gz) — media-agnostic,
|
|
482
|
+
* inputs may mix types. Returns a terminal {@link ArchivedRecipe} (a zip is
|
|
483
|
+
* the final artefact — no post-bundle chain). `format` / `folderStructure` are
|
|
484
|
+
* optional; the server defaults to zip + flat.
|
|
485
|
+
*
|
|
486
|
+
* `archive()` must be the FIRST op on `files([...])` → `GislConfigError` reason
|
|
487
|
+
* `pre_archive_ops_unsupported` otherwise.
|
|
488
|
+
*/
|
|
489
|
+
archive(options?: ArchiveRecipeOptions): ArchivedRecipe;
|
|
490
|
+
/** The number of inputs in this fan-out (introspection / tests). */
|
|
491
|
+
get inputCount(): number;
|
|
492
|
+
/** The number of operations chained so far (introspection / tests). */
|
|
493
|
+
get stepCount(): number;
|
|
494
|
+
/**
|
|
495
|
+
* Lower this fan-out to a single multi-job workflow-create payload against a
|
|
496
|
+
* list of resolved upload ids (one per input, in input order). Each input `i`
|
|
497
|
+
* becomes ONE job with `id = "file-{i}"`, its `source: upload(fileIds[i])`,
|
|
498
|
+
* and the SHARED lowered `operations[]`. Composes the single-file
|
|
499
|
+
* {@link Recipe.toWorkflowPayload} per file so per-file media-hints resolve
|
|
500
|
+
* independently and lowering logic is not duplicated.
|
|
501
|
+
*
|
|
502
|
+
* @internal Consumed by {@link run} (after uploading all inputs) and the
|
|
503
|
+
* cross-language parity harness (with fixed ids). Not caller-facing.
|
|
504
|
+
*/
|
|
505
|
+
toWorkflowPayload(fileIds: readonly string[], callbackUrl?: string): WorkflowCreatePayload;
|
|
506
|
+
/**
|
|
507
|
+
* Execute the fan-out end-to-end: upload EVERY input, create ONE workflow
|
|
508
|
+
* with one job per input, await a terminal state (SSE with poll fallback),
|
|
509
|
+
* then resolve the per-job downloads into a partitioned {@link RunResult}.
|
|
510
|
+
* `partially_failed` is a NORMAL terminal state here — its successful jobs
|
|
511
|
+
* land in `succeeded`, its failed jobs in `failed`.
|
|
512
|
+
*
|
|
513
|
+
* Requires a client bound at construction time — `gisl().files(...)` wires
|
|
514
|
+
* it; a directly-constructed `FilesRecipe` throws {@link GislConfigError}.
|
|
515
|
+
* Mirrors the single-file {@link Recipe.run}; see {@link submit} for the
|
|
516
|
+
* fire-and-forget arm.
|
|
517
|
+
*/
|
|
518
|
+
run(options?: {
|
|
519
|
+
maxWait?: string | number;
|
|
520
|
+
onProgress?: (event: ProgressEvent) => void;
|
|
521
|
+
signal?: AbortSignal;
|
|
522
|
+
pollIntervalMs?: number;
|
|
523
|
+
}): Promise<RunResult>;
|
|
524
|
+
/**
|
|
525
|
+
* Fire-and-forget the fan-out: upload every input, create ONE multi-job
|
|
526
|
+
* workflow (wiring `webhook` into `callback_url` when given), and return a
|
|
527
|
+
* client-bound {@link Handle}. Does NOT wait for terminal status — call
|
|
528
|
+
* `handle.wait()` / `handle.result()` later to collect the partitioned
|
|
529
|
+
* {@link RunResult}. The Handle detects the fan-out from the wire `file-{i}`
|
|
530
|
+
* job refs, so per-file `byKey()` works even after a `client.workflow(id)`
|
|
531
|
+
* reattach (the keys are the input indices `"0"`, `"1"`, …).
|
|
532
|
+
*
|
|
533
|
+
* Requires a client bound at construction time (same `no_client` guard as
|
|
534
|
+
* {@link run}). `webhook` is OPTIONAL. Fire-and-forget, so NO whole-run
|
|
535
|
+
* deadline (a multi-GB upload is bounded by the HTTP client's own timeout).
|
|
536
|
+
* Mirrors the single-file {@link Recipe.submit}.
|
|
537
|
+
*
|
|
538
|
+
* @param webhook Absolute callback URL the server POSTs lifecycle events to.
|
|
539
|
+
*/
|
|
540
|
+
submit(webhook?: string): Promise<Handle>;
|
|
541
|
+
/**
|
|
542
|
+
* Upload every input (verbatim for a pre-uploaded id; uploading a path /
|
|
543
|
+
* blob otherwise, emitting `{phase:'upload'}` progress) then create ONE
|
|
544
|
+
* multi-job workflow (one job per input, `callback_url` built in when
|
|
545
|
+
* `webhook` is given). Shared first half of {@link run} + {@link submit}.
|
|
546
|
+
*
|
|
547
|
+
* Uploads are sequential so progress events stay ordered and the abort
|
|
548
|
+
* signal is honoured promptly; a resource arm is impossible in TS (Blob).
|
|
549
|
+
* `run()` passes a whole-run deadline (a slow upload must not proceed to
|
|
550
|
+
* createWorkflow past maxWait); `submit()` passes `undefined`, so the
|
|
551
|
+
* deadline checks are skipped.
|
|
552
|
+
*/
|
|
553
|
+
private _uploadAllAndCreate;
|
|
554
|
+
/**
|
|
555
|
+
* The shared single-file {@link Recipe} that captures the op chain (input is
|
|
556
|
+
* a placeholder — only the steps are read). Reuses Recipe's op-chain
|
|
557
|
+
* validation + coercion so a `FilesRecipe.compress(bad)` throws the identical
|
|
558
|
+
* `GislConfigError` as `Recipe.compress(bad)`.
|
|
559
|
+
*/
|
|
560
|
+
private baseRecipe;
|
|
561
|
+
private withStep;
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* The single-output recipe you're in AFTER a fluent `files([...]).merge(...)`
|
|
565
|
+
* (FF3b). Merge collapses the N inputs into ONE output, so the per-file ops
|
|
566
|
+
* ({@link FilesRecipe.compress} etc.) no longer apply — instead this exposes the
|
|
567
|
+
* SAME chain ops as the single-file {@link Recipe}, applied to the merged
|
|
568
|
+
* result. `files([...]).merge().compress()` is the flagship case (example 14).
|
|
569
|
+
*
|
|
570
|
+
* **Lowering (one workflow):** each input is uploaded once and wrapped in its
|
|
571
|
+
* own single-input `passthrough` source job (`src_N`); the `merge` job consumes
|
|
572
|
+
* those via `job_output` inputs (array order = play order) and carries the merge
|
|
573
|
+
* op FIRST in its `operations[]`, followed by any post-combine ops (compress /
|
|
574
|
+
* convert / thumbnail) so they run on the merged output in the same job. The
|
|
575
|
+
* merge-level wire options reuse {@link wireMergeOptions} so a fluent merge
|
|
576
|
+
* lowers identically to the operation-first `client.merge()`.
|
|
577
|
+
*
|
|
578
|
+
* Immutable / clone-on-write like {@link Recipe} / {@link FilesRecipe}. Mirrors
|
|
579
|
+
* the PHP `MergedRecipe` in `packages/php/src/FileFirst/MergedRecipe.php`.
|
|
580
|
+
*/
|
|
581
|
+
export declare class MergedRecipe {
|
|
582
|
+
private readonly inputs;
|
|
583
|
+
private readonly mergeOptions;
|
|
584
|
+
private readonly postSteps;
|
|
585
|
+
private readonly presetDefaults?;
|
|
586
|
+
private readonly scopedPresetDefaults?;
|
|
587
|
+
private readonly client?;
|
|
588
|
+
constructor(inputs: readonly FileInput[], mergeOptions: MergeOptions, postSteps?: readonly RecipeStep[], presetDefaults?: PresetDefaults | undefined, scopedPresetDefaults?: PresetDefaults | undefined, client?: GislClient | undefined);
|
|
589
|
+
/** Reduce the merged output's size. See {@link Recipe.compress}. */
|
|
590
|
+
compress(optimize?: OptimizeFor): MergedRecipe;
|
|
591
|
+
/** Change the merged output's format. See {@link Recipe.convert}. */
|
|
592
|
+
convert(format: string): MergedRecipe;
|
|
593
|
+
/** Thumbnail the merged output. Omitted dimensions are dropped from the wire options. */
|
|
594
|
+
thumbnail(options?: {
|
|
595
|
+
width?: number;
|
|
596
|
+
height?: number;
|
|
597
|
+
}): MergedRecipe;
|
|
598
|
+
/**
|
|
599
|
+
* Lower to the merge DAG: one `passthrough` source job per input + one
|
|
600
|
+
* `merge` job whose `operations[]` is `[merge, ...post-combine ops]`. The
|
|
601
|
+
* merge job's `inputs[]` consume the source jobs via `job_output` in input
|
|
602
|
+
* (play) order.
|
|
603
|
+
*
|
|
604
|
+
* @internal Consumed by {@link run} (after uploading all inputs), {@link submit}
|
|
605
|
+
* (with a webhook), and the cross-language parity harness (with fixed ids).
|
|
606
|
+
*/
|
|
607
|
+
toWorkflowPayload(fileIds: readonly string[], callbackUrl?: string): WorkflowCreatePayload;
|
|
608
|
+
/** The number of inputs being combined (introspection / tests). */
|
|
609
|
+
get inputCount(): number;
|
|
610
|
+
/** The number of post-combine ops chained so far (introspection / tests). */
|
|
611
|
+
get stepCount(): number;
|
|
612
|
+
/**
|
|
613
|
+
* Execute end-to-end: upload every input, create the merge workflow, await a
|
|
614
|
+
* terminal state (SSE with poll fallback), then resolve ONLY the merged output
|
|
615
|
+
* into a {@link RunResult}. Throws {@link GislTimeoutError} on `maxWait`.
|
|
616
|
+
*
|
|
617
|
+
* Requires a client bound at construction time — `gisl().files(...).merge(...)`
|
|
618
|
+
* wires it; a directly-constructed `MergedRecipe` throws {@link GislConfigError}.
|
|
619
|
+
* Mirrors the single-file {@link Recipe.run}.
|
|
620
|
+
*/
|
|
621
|
+
run(options?: {
|
|
622
|
+
maxWait?: string | number;
|
|
623
|
+
onProgress?: (event: ProgressEvent) => void;
|
|
624
|
+
signal?: AbortSignal;
|
|
625
|
+
pollIntervalMs?: number;
|
|
626
|
+
}): Promise<RunResult>;
|
|
627
|
+
/**
|
|
628
|
+
* Fire-and-forget: upload + create the merge workflow (wiring `webhook` into
|
|
629
|
+
* `callback_url` when given), return a client-bound {@link Handle}. Does NOT
|
|
630
|
+
* wait for terminal status. Mirrors {@link Recipe.submit}.
|
|
631
|
+
*/
|
|
632
|
+
submit(webhook?: string): Promise<Handle>;
|
|
633
|
+
/**
|
|
634
|
+
* Upload every input (verbatim for a pre-uploaded id; uploading a path / blob
|
|
635
|
+
* otherwise, emitting `{phase:'upload'}` progress) then create ONE merge
|
|
636
|
+
* workflow. Rejects fewer than 2 inputs BEFORE any upload fires. Shared first
|
|
637
|
+
* half of {@link run} + {@link submit}.
|
|
638
|
+
*/
|
|
639
|
+
private _uploadAllAndCreate;
|
|
640
|
+
/**
|
|
641
|
+
* Reject an invalid combine BEFORE any upload fires — mirrors the operation-
|
|
642
|
+
* first `MergeBuilder.planSequence()` bounds so a typo'd merge costs no
|
|
643
|
+
* bandwidth: 2–10 inputs (merge schema `min/max_inputs`), and an image merge
|
|
644
|
+
* must carry an explicit `output_type` (the server rejects image merges
|
|
645
|
+
* without one). Shared by {@link run} + {@link submit} via
|
|
646
|
+
* {@link _uploadAllAndCreate}.
|
|
647
|
+
*/
|
|
648
|
+
private validatePreUpload;
|
|
649
|
+
/**
|
|
650
|
+
* Lower the post-combine chain by composing a single-file {@link Recipe} over a
|
|
651
|
+
* synthetic input whose extension matches the merged OUTPUT media — so
|
|
652
|
+
* `compress(optimize)` resolves the correct preset for the merged result (it
|
|
653
|
+
* needs a media hint, which a merge output carries no filename for). Reuses
|
|
654
|
+
* Recipe's `lowerStep` rather than duplicating it.
|
|
655
|
+
*/
|
|
656
|
+
private lowerPostSteps;
|
|
657
|
+
/**
|
|
658
|
+
* The merged-output media. Honours an explicit {@link MergeOptions.mediaKind};
|
|
659
|
+
* otherwise infers from the first PATH input's extension (mirrors
|
|
660
|
+
* {@link MergeBuilder}); defaults to video.
|
|
661
|
+
*/
|
|
662
|
+
private inferMediaKind;
|
|
663
|
+
private outputExtensionFor;
|
|
664
|
+
private withStep;
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* Options for a fluent `files([...]).archive(...)` bundle. Both fields are
|
|
668
|
+
* optional — the server defaults `format` to `zip` and `folderStructure` to
|
|
669
|
+
* `flat` (archive op schema). Mirrors the PHP `ArchivedRecipe` ctor params.
|
|
670
|
+
*/
|
|
671
|
+
export interface ArchiveRecipeOptions {
|
|
672
|
+
/** Archive container format. */
|
|
673
|
+
readonly format?: 'zip' | 'tar.gz';
|
|
674
|
+
/** `flat` = all files at the top level; `by_job` = a subfolder per source. */
|
|
675
|
+
readonly folderStructure?: 'flat' | 'by_job';
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* The single-output recipe you're in AFTER a fluent `files([...]).archive(...)`
|
|
679
|
+
* (FF3b). Archive bundles the N inputs into ONE downloadable archive (zip /
|
|
680
|
+
* tar.gz) — media-agnostic, inputs may mix types. Unlike {@link MergedRecipe},
|
|
681
|
+
* archive is TERMINAL: a zip is the final artefact, so there is no post-bundle
|
|
682
|
+
* chain — this exposes only `run()` / `submit()`.
|
|
683
|
+
*
|
|
684
|
+
* **Lowering (one workflow):** each input is uploaded once and wrapped in its
|
|
685
|
+
* own single-input `passthrough` source job (`src_N`); the `archive` job
|
|
686
|
+
* consumes those via `job_output` inputs (array order = entry order) and carries
|
|
687
|
+
* the single `archive` op. The archive job's id is `archive`, so {@link RunResult}
|
|
688
|
+
* projects ONLY its output. Mirrors the PHP `ArchivedRecipe`.
|
|
689
|
+
*/
|
|
690
|
+
export declare class ArchivedRecipe {
|
|
691
|
+
private readonly inputs;
|
|
692
|
+
private readonly options;
|
|
693
|
+
private readonly client?;
|
|
694
|
+
constructor(inputs: readonly FileInput[], options?: ArchiveRecipeOptions, client?: GislClient | undefined);
|
|
695
|
+
/** The number of inputs being bundled (introspection / tests). */
|
|
696
|
+
get inputCount(): number;
|
|
697
|
+
/**
|
|
698
|
+
* Lower to the archive DAG: one `passthrough` source job per input + one
|
|
699
|
+
* `archive` job consuming them via `job_output`.
|
|
700
|
+
*
|
|
701
|
+
* @internal Consumed by {@link run} / {@link submit} (after uploading) and the
|
|
702
|
+
* cross-language parity harness (with fixed ids).
|
|
703
|
+
*/
|
|
704
|
+
toWorkflowPayload(fileIds: readonly string[], callbackUrl?: string): WorkflowCreatePayload;
|
|
705
|
+
/**
|
|
706
|
+
* Execute end-to-end: upload every input, create the archive workflow, await a
|
|
707
|
+
* terminal state (SSE with poll fallback), then resolve ONLY the archive output
|
|
708
|
+
* into a {@link RunResult}. Throws {@link GislTimeoutError} on `maxWait`.
|
|
709
|
+
* Requires a client bound via `gisl().files(...).archive(...)`.
|
|
710
|
+
*/
|
|
711
|
+
run(options?: {
|
|
712
|
+
maxWait?: string | number;
|
|
713
|
+
onProgress?: (event: ProgressEvent) => void;
|
|
714
|
+
signal?: AbortSignal;
|
|
715
|
+
pollIntervalMs?: number;
|
|
716
|
+
}): Promise<RunResult>;
|
|
717
|
+
/**
|
|
718
|
+
* Fire-and-forget: upload + create the archive workflow (wiring `webhook` into
|
|
719
|
+
* `callback_url` when given), return a client-bound {@link Handle}. Mirrors
|
|
720
|
+
* {@link MergedRecipe.submit}.
|
|
721
|
+
*/
|
|
722
|
+
submit(webhook?: string): Promise<Handle>;
|
|
723
|
+
private _uploadAllAndCreate;
|
|
724
|
+
/**
|
|
725
|
+
* Reject an invalid bundle BEFORE any upload fires — the archive schema allows
|
|
726
|
+
* 2–50 inputs (`min/max_inputs`), so a typo'd bundle costs no bandwidth.
|
|
727
|
+
*/
|
|
728
|
+
private validatePreUpload;
|
|
729
|
+
/**
|
|
730
|
+
* Project the archive options into the wire shape. Both fields are optional
|
|
731
|
+
* (the server defaults `format` to zip and `folder_structure` to flat), so an
|
|
732
|
+
* omitted option is dropped rather than sent.
|
|
733
|
+
*/
|
|
734
|
+
private wireArchiveOptions;
|
|
735
|
+
}
|
|
284
736
|
export {};
|