@giveitsmaller/sdk 0.20.0 → 0.22.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.
Files changed (40) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +55 -14
  3. package/dist/_audit.js +2 -4
  4. package/dist/builder.d.ts +4 -4
  5. package/dist/builder.js +47 -22
  6. package/dist/client.d.ts +9 -6
  7. package/dist/client.js +90 -31
  8. package/dist/ergonomic/image_output_routes.d.ts +97 -0
  9. package/dist/ergonomic/image_output_routes.js +227 -25
  10. package/dist/ergonomic/option_types.d.ts +11 -2
  11. package/dist/ergonomic/preset_resolver.d.ts +24 -2
  12. package/dist/ergonomic/preset_resolver.js +100 -10
  13. package/dist/ergonomic/presets/image_compress.js +16 -4
  14. package/dist/ergonomic/presets/index.d.ts +9 -8
  15. package/dist/ergonomic/presets/index.js +1 -9
  16. package/dist/ergonomic/presets/video_compress.d.ts +14 -0
  17. package/dist/errors.d.ts +101 -2
  18. package/dist/errors.js +108 -1
  19. package/dist/file-first.d.ts +81 -13
  20. package/dist/file-first.js +329 -69
  21. package/dist/generated/sdk_spec/enums.d.ts +0 -26
  22. package/dist/generated/sdk_spec/enums.js +0 -16
  23. package/dist/generated/sdk_spec/errors.d.ts +1 -1
  24. package/dist/generated/sdk_spec/errors.js +159 -1
  25. package/dist/generated/sdk_spec/presets.js +0 -14
  26. package/dist/generated/sdk_spec/version.d.ts +2 -2
  27. package/dist/generated/sdk_spec/version.js +2 -2
  28. package/dist/gisl.d.ts +21 -2
  29. package/dist/handle.d.ts +6 -1
  30. package/dist/handle.js +42 -13
  31. package/dist/index.core.d.ts +4 -4
  32. package/dist/index.core.js +6 -3
  33. package/dist/merge.d.ts +23 -0
  34. package/dist/merge.js +2 -2
  35. package/dist/sse.js +49 -1
  36. package/dist/types.d.ts +11 -3
  37. package/dist/types.js +1 -0
  38. package/package.json +3 -3
  39. package/dist/ergonomic/presets/document_pdf_compress.d.ts +0 -12
  40. package/dist/ergonomic/presets/document_pdf_compress.js +0 -33
@@ -63,20 +63,6 @@ export declare const AudioSampleRate: {
63
63
  readonly _48000: 48000;
64
64
  };
65
65
  export type AudioSampleRate = typeof AudioSampleRate[keyof typeof AudioSampleRate];
66
- export declare const PdfProfile: {
67
- readonly Screen: "screen";
68
- readonly Ebook: "ebook";
69
- readonly Printer: "printer";
70
- readonly Prepress: "prepress";
71
- };
72
- export type PdfProfile = typeof PdfProfile[keyof typeof PdfProfile];
73
- export declare const PdfColorspace: {
74
- readonly Unchanged: "unchanged";
75
- readonly Rgb: "rgb";
76
- readonly Cmyk: "cmyk";
77
- readonly Grayscale: "grayscale";
78
- };
79
- export type PdfColorspace = typeof PdfColorspace[keyof typeof PdfColorspace];
80
66
  /** Catalog of every ergonomic enum (canonicalName → wire). */
81
67
  export declare const ERGONOMIC_ENUMS: {
82
68
  readonly OptimizeFor: {
@@ -135,16 +121,4 @@ export declare const ERGONOMIC_ENUMS: {
135
121
  readonly _44100: 44100;
136
122
  readonly _48000: 48000;
137
123
  };
138
- readonly PdfProfile: {
139
- readonly Screen: "screen";
140
- readonly Ebook: "ebook";
141
- readonly Printer: "printer";
142
- readonly Prepress: "prepress";
143
- };
144
- readonly PdfColorspace: {
145
- readonly Unchanged: "unchanged";
146
- readonly Rgb: "rgb";
147
- readonly Cmyk: "cmyk";
148
- readonly Grayscale: "grayscale";
149
- };
150
124
  };
@@ -77,20 +77,6 @@ export const AudioSampleRate = {
77
77
  _44100: 44100,
78
78
  _48000: 48000,
79
79
  };
80
- // PDF Ghostscript preset. Screen = smallest; Ebook = mid; Printer = 300dpi; Prepress = print-production.
81
- export const PdfProfile = {
82
- Screen: "screen",
83
- Ebook: "ebook",
84
- Printer: "printer",
85
- Prepress: "prepress",
86
- };
87
- // PDF output color space.
88
- export const PdfColorspace = {
89
- Unchanged: "unchanged",
90
- Rgb: "rgb",
91
- Cmyk: "cmyk",
92
- Grayscale: "grayscale",
93
- };
94
80
  /** Catalog of every ergonomic enum (canonicalName → wire). */
95
81
  export const ERGONOMIC_ENUMS = {
96
82
  OptimizeFor,
@@ -102,6 +88,4 @@ export const ERGONOMIC_ENUMS = {
102
88
  AudioBitrate,
103
89
  AudioCodec,
104
90
  AudioSampleRate,
105
- PdfProfile,
106
- PdfColorspace,
107
91
  };
@@ -1,4 +1,4 @@
1
- export type ErrorCode = "missing_credentials" | "feature_requires_auth" | "undeclared_asset" | "unused_asset" | "per_input_options_not_supported" | "chain_cardinality_mismatch" | "multipart_part_invalid" | "multipart_part_count_exceeded" | "timeout" | "aborted" | "validation_failed" | "validation_error" | "cyclic_workflow_edges" | "workflow_edge_references_unknown_job" | "reserved_job_id_pattern" | "cyclic_job_output_source_graph" | "auth_failed" | "feature_tier_restricted" | "tier_restriction" | "multipart_session_ownership" | "multipart_session_auth_required" | "multipart_session_not_found" | "upload_not_found" | "workflow_expired" | "balance_exhausted" | "feature_not_available" | "upload_size_exceeds_tier" | "upload_duration_exceeds_tier" | "probe_pending" | "requires_reencode" | "invalid_options" | "invalid_combination" | "missing_dependency" | "unsupported_value" | "type_mismatch" | "upload_failed" | "workflow_failed";
1
+ export type ErrorCode = "missing_credentials" | "feature_requires_auth" | "undeclared_asset" | "unused_asset" | "per_input_options_not_supported" | "chain_cardinality_mismatch" | "multipart_part_invalid" | "multipart_part_count_exceeded" | "timeout" | "aborted" | "validation_failed" | "validation_error" | "cyclic_workflow_edges" | "workflow_edge_references_unknown_job" | "reserved_job_id_pattern" | "cyclic_job_output_source_graph" | "auth_failed" | "feature_tier_restricted" | "tier_restriction" | "multipart_session_ownership" | "multipart_session_auth_required" | "multipart_session_not_found" | "upload_not_found" | "workflow_expired" | "balance_exhausted" | "feature_not_available" | "upload_size_exceeds_tier" | "upload_duration_exceeds_tier" | "probe_pending" | "requires_reencode" | "invalid_options" | "invalid_combination" | "missing_dependency" | "unsupported_value" | "type_mismatch" | "image_dimensions_too_large" | "upload_failed" | "workflow_failed" | "long_form_concurrency_limit_exceeded" | "unprocessable_entity" | "email_same" | "config_error" | "bundle_already_archived" | "fan_out_timeout" | "no_such_key" | "result_not_ready" | "sink_error" | "item_failed";
2
2
  export type ErrorCategory = 'api' | 'config' | 'network' | 'auth' | 'validation' | 'chain';
3
3
  export type ErrorStatus = 'wired' | 'planned';
4
4
  export interface ErrorEntry {
@@ -377,7 +377,7 @@ export const ERROR_CODES = Object.freeze({
377
377
  status: "wired",
378
378
  httpStatus: 422,
379
379
  retryable: true,
380
- sdkClass: "GislApiError",
380
+ sdkClass: "GislProbePendingError",
381
381
  description: "422 on workflow create — upload probing not yet complete; retry after the upload finishes probing. Wire `error_type: \"probe_pending\"`.",
382
382
  metadataSchema: Object.freeze({
383
383
  "jobRef": "string",
@@ -467,6 +467,17 @@ export const ERROR_CODES = Object.freeze({
467
467
  "actual": "string",
468
468
  }),
469
469
  }),
470
+ "image_dimensions_too_large": Object.freeze({
471
+ code: "image_dimensions_too_large",
472
+ category: "api",
473
+ source: "ErrorEnvelope.error",
474
+ status: "wired",
475
+ httpStatus: 413,
476
+ retryable: false,
477
+ sdkClass: "GislUploadCapExceededError",
478
+ description: "413 — POST /api/uploads rejected a decodable raster image whose pixel area (width × height) exceeds the configured ceiling (UPLOAD_MAX_IMAGE_PIXELS, default 16 MP), read from the file header before decode (I0Rqj4jo). Wire `IMAGE_DIMENSIONS_TOO_LARGE`; flat ErrorEnvelope (no details[]). A pixel-dimension member of the upload-cap family — GislUploadCapExceededError, alongside the size/duration caps — matching the SDKs' existing status-based 413 dispatch (NOT GislValidationError, which is the structured-422 class). Retry only after downscaling the input.",
479
+ metadataSchema: Object.freeze({}),
480
+ }),
470
481
  "upload_failed": Object.freeze({
471
482
  code: "upload_failed",
472
483
  category: "network",
@@ -495,6 +506,142 @@ export const ERROR_CODES = Object.freeze({
495
506
  "jobErrors": "array",
496
507
  }),
497
508
  }),
509
+ "long_form_concurrency_limit_exceeded": Object.freeze({
510
+ code: "long_form_concurrency_limit_exceeded",
511
+ category: "api",
512
+ source: "ErrorEnvelope.error",
513
+ status: "wired",
514
+ httpStatus: 429,
515
+ retryable: false,
516
+ sdkClass: "GislLongFormConcurrencyError",
517
+ description: "429 — the caller's tier long-form concurrency allowance is exhausted. Wire value is UPPERCASE `LONG_FORM_CONCURRENCY_LIMIT_EXCEEDED` (api.yaml:1995); this file's `code:` follows the taxonomy's lowercase convention. Dispatched on the machine `error` code, NOT on the status: a generic infra rate-limit 429 carries a different/absent code and falls through to base GislApiError where retryAfterSeconds applies. Do not widen this entry to the status.",
518
+ metadataSchema: Object.freeze({
519
+ "currentTier": "string",
520
+ "maxDurationSeconds": "number",
521
+ }),
522
+ }),
523
+ "unprocessable_entity": Object.freeze({
524
+ code: "unprocessable_entity",
525
+ category: "auth",
526
+ source: "error_type",
527
+ status: "wired",
528
+ httpStatus: 422,
529
+ retryable: false,
530
+ sdkClass: "GislAuthRejectionError",
531
+ description: "422 on an auth-side-effect endpoint (register / verify-email / api-keys) — the request was well-formed but rejected on domain grounds. Dispatched on MEMBERSHIP of AuthRejectionEnvelope.error_type, per ADR-0019.",
532
+ metadataSchema: Object.freeze({
533
+ "errorType": "string",
534
+ }),
535
+ }),
536
+ "email_same": Object.freeze({
537
+ code: "email_same",
538
+ category: "auth",
539
+ source: "error_type",
540
+ status: "wired",
541
+ httpStatus: 422,
542
+ retryable: false,
543
+ sdkClass: "GislAuthRejectionError",
544
+ description: "422 on profile PATCH — the submitted email matches the current one, so there is nothing to change. Same envelope and sdkClass as unprocessable_entity; separate row because the wire value differs.",
545
+ metadataSchema: Object.freeze({
546
+ "errorType": "string",
547
+ }),
548
+ }),
549
+ "config_error": Object.freeze({
550
+ code: "config_error",
551
+ category: "config",
552
+ source: "SDK_local",
553
+ status: "wired",
554
+ httpStatus: null,
555
+ retryable: false,
556
+ sdkClass: "GislConfigError",
557
+ description: "Client-side configuration rejected before any request — thrown directly (preset resolver, output() gates), not only as a base class. `reason` carries the discriminator: `unknown_field` and `type_mismatch` are values of THIS field and deliberately have no rows of their own.",
558
+ metadataSchema: Object.freeze({
559
+ "reason": "string",
560
+ "conflictingFields": "array",
561
+ "resolvedSnapshot": "object",
562
+ "suggestion": "string",
563
+ }),
564
+ }),
565
+ "bundle_already_archived": Object.freeze({
566
+ code: "bundle_already_archived",
567
+ category: "config",
568
+ source: "SDK_local",
569
+ status: "planned",
570
+ httpStatus: null,
571
+ retryable: false,
572
+ sdkClass: "GislBundleAlreadyArchivedError",
573
+ description: "PLANNED — not reachable in any shipped build. Raised when a bundle operation targets an already-archived bundle, once `.bundle()` ships. Do not write handler code against this yet.",
574
+ metadataSchema: Object.freeze({}),
575
+ }),
576
+ "fan_out_timeout": Object.freeze({
577
+ code: "fan_out_timeout",
578
+ category: "network",
579
+ source: "SDK_local",
580
+ status: "wired",
581
+ httpStatus: null,
582
+ retryable: true,
583
+ sdkClass: "GislFanOutTimeoutError",
584
+ description: "A fan-out deadline elapsed before all children finished. The three metadata fields are the reason this is declared separately from GislTimeoutError: completedWorkflowIds are the children that DID finish, parentWorkflowId ran to completion before the fan-out began, and the inherited workflowId is the in-flight child — absent on a clean between-children timeout.",
585
+ metadataSchema: Object.freeze({
586
+ "completedWorkflowIds": "array",
587
+ "parentWorkflowId": "string",
588
+ "workflowId": "string",
589
+ }),
590
+ }),
591
+ "no_such_key": Object.freeze({
592
+ code: "no_such_key",
593
+ category: "chain",
594
+ source: "SDK_local",
595
+ status: "wired",
596
+ httpStatus: null,
597
+ retryable: false,
598
+ sdkClass: "GislNoSuchKeyError",
599
+ description: "The caller asked for a mapEach result key that does not exist in the output. NOTE the key itself is NOT captured in metadata today — it is interpolated into the message only, so consumers cannot branch on which key was missing.",
600
+ metadataSchema: Object.freeze({}),
601
+ }),
602
+ "result_not_ready": Object.freeze({
603
+ code: "result_not_ready",
604
+ category: "validation",
605
+ source: "SDK_local",
606
+ status: "wired",
607
+ httpStatus: null,
608
+ retryable: true,
609
+ sdkClass: "GislResultNotReadyError",
610
+ description: "The caller read a result before the workflow reached a terminal state. `state` carries the non-terminal status observed.",
611
+ metadataSchema: Object.freeze({
612
+ "workflowId": "string",
613
+ "state": "string",
614
+ }),
615
+ }),
616
+ "sink_error": Object.freeze({
617
+ code: "sink_error",
618
+ category: "config",
619
+ source: "SDK_local",
620
+ status: "wired",
621
+ httpStatus: null,
622
+ retryable: false,
623
+ sdkClass: "GislSinkError",
624
+ description: "A caller-supplied output sink could not be used. Branch on `reason` — the values span both caller setup (invalid_directory, duplicate_filename) and runtime write outcomes (write_failed, partial_failure), so the category is a best fit rather than an exact one.",
625
+ metadataSchema: Object.freeze({
626
+ "reason": "string",
627
+ }),
628
+ }),
629
+ "item_failed": Object.freeze({
630
+ code: "item_failed",
631
+ category: "api",
632
+ source: "SDK_local",
633
+ status: "wired",
634
+ httpStatus: null,
635
+ retryable: false,
636
+ sdkClass: "GislItemFailedError",
637
+ description: "CARRIED, not thrown — an entry in a per-item failed[] collection describing one item's server-side failure. `errorCode` carries the server's own code where present; prefer branching on that over this entry.",
638
+ metadataSchema: Object.freeze({
639
+ "key": "string",
640
+ "state": "string",
641
+ "errorMessage": "string",
642
+ "errorCode": "string",
643
+ }),
644
+ }),
498
645
  });
499
646
  export const ERROR_CATEGORIES = Object.freeze({
500
647
  api: Object.freeze([
@@ -509,21 +656,30 @@ export const ERROR_CATEGORIES = Object.freeze({
509
656
  "upload_duration_exceeds_tier",
510
657
  "probe_pending",
511
658
  "requires_reencode",
659
+ "image_dimensions_too_large",
512
660
  "workflow_failed",
661
+ "long_form_concurrency_limit_exceeded",
662
+ "item_failed",
513
663
  ]),
514
664
  config: Object.freeze([
515
665
  "missing_credentials",
516
666
  "feature_requires_auth",
667
+ "config_error",
668
+ "bundle_already_archived",
669
+ "sink_error",
517
670
  ]),
518
671
  network: Object.freeze([
519
672
  "timeout",
520
673
  "aborted",
521
674
  "upload_failed",
675
+ "fan_out_timeout",
522
676
  ]),
523
677
  auth: Object.freeze([
524
678
  "auth_failed",
525
679
  "multipart_session_ownership",
526
680
  "multipart_session_auth_required",
681
+ "unprocessable_entity",
682
+ "email_same",
527
683
  ]),
528
684
  validation: Object.freeze([
529
685
  "multipart_part_invalid",
@@ -539,11 +695,13 @@ export const ERROR_CATEGORIES = Object.freeze({
539
695
  "missing_dependency",
540
696
  "unsupported_value",
541
697
  "type_mismatch",
698
+ "result_not_ready",
542
699
  ]),
543
700
  chain: Object.freeze([
544
701
  "undeclared_asset",
545
702
  "unused_asset",
546
703
  "per_input_options_not_supported",
547
704
  "chain_cardinality_mismatch",
705
+ "no_such_key",
548
706
  ]),
549
707
  });
@@ -50,20 +50,6 @@ export const PRESETS = Object.freeze({
50
50
  "preset": "Slow",
51
51
  }),
52
52
  }),
53
- "document_pdf_compress": Object.freeze({
54
- Size: Object.freeze({
55
- "profile": "Screen",
56
- "grayscale": true,
57
- }),
58
- Balanced: Object.freeze({
59
- "profile": "Ebook",
60
- "grayscale": false,
61
- }),
62
- Quality: Object.freeze({
63
- "profile": "Printer",
64
- "grayscale": false,
65
- }),
66
- }),
67
53
  "document_office_compress": Object.freeze({
68
54
  Size: Object.freeze({
69
55
  "stripMacros": true,
@@ -1,3 +1,3 @@
1
- export declare const SDK_SPEC_VERSION: "2.2.0";
1
+ export declare const SDK_SPEC_VERSION: "2.3.0";
2
2
  export declare const PRESET_VERSION: "1.6";
3
- export declare const PRESET_CONFIG_HASH: "sha256:0fe215aede1da13430380384c58226d074c3b8344c091efc53e097c2930a34f7";
3
+ export declare const PRESET_CONFIG_HASH: "sha256:354814f7906f85be6a6ca5ede6c0722c83cdc058fd658a9bb2b0996520466c6d";
@@ -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.2.0";
4
+ export const SDK_SPEC_VERSION = "2.3.0";
5
5
  export const PRESET_VERSION = "1.6";
6
- export const PRESET_CONFIG_HASH = "sha256:0fe215aede1da13430380384c58226d074c3b8344c091efc53e097c2930a34f7";
6
+ export const PRESET_CONFIG_HASH = "sha256:354814f7906f85be6a6ca5ede6c0722c83cdc058fd658a9bb2b0996520466c6d";
package/dist/gisl.d.ts CHANGED
@@ -22,6 +22,7 @@ import { type ResolveCredentialsOptions, type ResolveEndpointOptions } from './c
22
22
  import type { CreditsUsageOptions, GislClientConfig, CapabilitiesSnapshot } from './types.js';
23
23
  import type { AccountLimits, CreditsBalanceResponse, CreditsUsageResponse, OperationCapability, OperationType } from '@giveitsmaller/contracts/openapi';
24
24
  import { OperationBuilder } from './builder.js';
25
+ import type { ConvertOptions, ThumbnailOptions } from './ergonomic/option_types.js';
25
26
  import { MergeBuilder, type Asset, type MergeOptions } from './merge.js';
26
27
  import { PresetDefaults } from './ergonomic/presets/index.js';
27
28
  import { Recipe, FilesRecipe, BatchRecipe, type FileInput } from './file-first.js';
@@ -129,8 +130,26 @@ export type ErgonomicClient = GislClient & {
129
130
  */
130
131
  workflow(id: string): Handle;
131
132
  compress(input: string | Blob, options?: Record<string, unknown>): OperationBuilder;
132
- convert(input: string | Blob, options?: Record<string, unknown>): OperationBuilder;
133
- thumbnail(input: string | Blob, options?: Record<string, unknown>): OperationBuilder;
133
+ /**
134
+ * Single-op convert. The target format rides the bag as the required
135
+ * `output_format` (the single-op builder has no positional format — that is
136
+ * the file-first `Recipe.convert(format, …)` surface). Extra keys are the
137
+ * typed {@link ConvertOptions}. A missing `output_format` is a compile-time
138
+ * error (uFbM31dC); an unknown key is a compile-time error for an INLINE bag
139
+ * only — aliased bags bypass TS excess-property checks — so the runtime guard
140
+ * remains the backstop (also for untyped JS callers).
141
+ */
142
+ convert(input: string | Blob, options: ConvertOptions & {
143
+ output_format: string;
144
+ }): OperationBuilder;
145
+ /**
146
+ * Single-op thumbnail. {@link ThumbnailOptions} requires `width` + `height`;
147
+ * omitting either is a compile-time error (uFbM31dC). An unknown key is a
148
+ * compile-time error for an INLINE bag only — aliased bags bypass TS
149
+ * excess-property checks — so the runtime guard remains the backstop (also
150
+ * for untyped JS callers).
151
+ */
152
+ thumbnail(input: string | Blob, options: ThumbnailOptions): OperationBuilder;
134
153
  /** Geometric transform (rotate/flip). Passthrough; the op is `planned` (server 422s until Lambdas ship). */
135
154
  transform(input: string | Blob, options?: Record<string, unknown>): OperationBuilder;
136
155
  /**
package/dist/handle.d.ts CHANGED
@@ -97,7 +97,7 @@ export declare class Handle {
97
97
  * This is the ONLY blocking accessor on a `Handle`.
98
98
  *
99
99
  * @param maxWait Wall-clock deadline for the wait + downloads (string suffix
100
- * `'2h'`/`'30m'`/`'120s'` or a number of milliseconds). Defaults to 300s,
100
+ * `'2h'`/`'30m'`/`'120s'` or a number of milliseconds). Defaults to 600s,
101
101
  * matching `Recipe.run()` / the PHP `Handle::wait()` default.
102
102
  * @throws {GislConfigError} reason `no_client` when no client is bound.
103
103
  * @throws {GislTimeoutError} when `maxWait` elapses before terminal.
@@ -125,6 +125,11 @@ export declare class Handle {
125
125
  * empty `keyByRef`, so each input's key is recovered from its `file-{i}`
126
126
  * ref (`"0"`, `"1"`, …). A submitted/reattached fan-out carries no
127
127
  * caller-supplied keys — keyed fan-out is a separate concern.
128
+ * - A `merge` / `archive` / `watermark` shape ({@link isMergeStatus} /
129
+ * {@link isArchiveStatus} / {@link isWatermarkStatus}) → project ONLY the
130
+ * terminal deliverable, filtering the `src_*` passthrough plumbing. The
131
+ * terminal ref is the downstream `post` job when post-`sole_op` steps were
132
+ * chained ({@link terminalOutputRef}), else the sole_op job itself.
128
133
  * - Anything else (the single-file {@link Recipe} path) →
129
134
  * {@link projectDownloadsToRunResult} keyed by this handle's `#key`
130
135
  * (the recipe key from a file-first `submit()`, or `null` on reattach).
package/dist/handle.js CHANGED
@@ -34,7 +34,7 @@
34
34
  */
35
35
  import { GislConfigError, GislNetworkError, GislResultNotReadyError, GislTimeoutError, SseEndedWithoutTerminal, } from './errors.js';
36
36
  import { _consumeSseToTerminal, _pollToTerminal, _parseMaxWait, } from './builder.js';
37
- import { projectDownloadsToRunResult, projectMultiJobToRunResult, isFanoutStatus, isMergeStatus, isArchiveStatus, isWatermarkStatus, } from './file-first.js';
37
+ import { projectDownloadsToRunResult, projectMultiJobToRunResult, isFanoutStatus, isMergeStatus, isArchiveStatus, isWatermarkStatus, isSoleOpChainStatus, soleOpChainDeliverableRef, _POST_STEP_JOB_REF, } from './file-first.js';
38
38
  import { LazyHttpDownloader } from './lazy-downloader.js';
39
39
  /**
40
40
  * The terminal workflow states. A status response in any of these states
@@ -80,6 +80,16 @@ export class StatusSnapshot {
80
80
  return { workflowId: this.workflowId, state: this.state };
81
81
  }
82
82
  }
83
+ /**
84
+ * The terminal deliverable's job ref for a `sole_op` DAG: the downstream
85
+ * post-steps job ({@link _POST_STEP_JOB_REF}, present when the caller chained
86
+ * ops after `watermark()` / `merge()`) when it exists, else the `sole_op` job
87
+ * itself. Lets a submitted/reattached {@link Handle} project the final output —
88
+ * not the intermediate `sole_op` artifact — without builder state. PIiUit28.
89
+ */
90
+ function terminalOutputRef(jobDownloads, soleOpRef) {
91
+ return jobDownloads.some((d) => d.ref === _POST_STEP_JOB_REF) ? _POST_STEP_JOB_REF : soleOpRef;
92
+ }
83
93
  /**
84
94
  * Handle to a created workflow. Carries `workflowId` + an optional
85
95
  * `webhookSecret` (the data the operation-first/merge `submit()` returns)
@@ -139,12 +149,12 @@ export class Handle {
139
149
  * This is the ONLY blocking accessor on a `Handle`.
140
150
  *
141
151
  * @param maxWait Wall-clock deadline for the wait + downloads (string suffix
142
- * `'2h'`/`'30m'`/`'120s'` or a number of milliseconds). Defaults to 300s,
152
+ * `'2h'`/`'30m'`/`'120s'` or a number of milliseconds). Defaults to 600s,
143
153
  * matching `Recipe.run()` / the PHP `Handle::wait()` default.
144
154
  * @throws {GislConfigError} reason `no_client` when no client is bound.
145
155
  * @throws {GislTimeoutError} when `maxWait` elapses before terminal.
146
156
  */
147
- async wait(maxWait = 300_000, onProgress) {
157
+ async wait(maxWait = 600_000, onProgress) {
148
158
  const client = this.requireClient();
149
159
  const deadline = Date.now() + _parseMaxWait(maxWait);
150
160
  let finalStatus;
@@ -172,13 +182,13 @@ export class Handle {
172
182
  });
173
183
  }
174
184
  if (Date.now() >= deadline) {
175
- throw new GislTimeoutError(`Workflow ${this.workflowId} reached terminal status but maxWait elapsed before downloads could be fetched`);
185
+ throw new GislTimeoutError(`Workflow ${this.workflowId} reached terminal status but maxWait elapsed before downloads could be fetched`, this.workflowId);
176
186
  }
177
187
  const downloads = await client.getWorkflowDownloads(this.workflowId);
178
188
  // TDqmkWpX: re-check AFTER the downloads fetch so a slow getWorkflowDownloads
179
189
  // cannot return a success past the advertised maxWait.
180
190
  if (Date.now() >= deadline) {
181
- throw new GislTimeoutError(`Workflow ${this.workflowId} downloads fetch completed after maxWait elapsed`);
191
+ throw new GislTimeoutError(`Workflow ${this.workflowId} downloads fetch completed after maxWait elapsed`, this.workflowId);
182
192
  }
183
193
  return this.project(finalStatus, downloads.downloads);
184
194
  }
@@ -212,6 +222,11 @@ export class Handle {
212
222
  * empty `keyByRef`, so each input's key is recovered from its `file-{i}`
213
223
  * ref (`"0"`, `"1"`, …). A submitted/reattached fan-out carries no
214
224
  * caller-supplied keys — keyed fan-out is a separate concern.
225
+ * - A `merge` / `archive` / `watermark` shape ({@link isMergeStatus} /
226
+ * {@link isArchiveStatus} / {@link isWatermarkStatus}) → project ONLY the
227
+ * terminal deliverable, filtering the `src_*` passthrough plumbing. The
228
+ * terminal ref is the downstream `post` job when post-`sole_op` steps were
229
+ * chained ({@link terminalOutputRef}), else the sole_op job itself.
215
230
  * - Anything else (the single-file {@link Recipe} path) →
216
231
  * {@link projectDownloadsToRunResult} keyed by this handle's `#key`
217
232
  * (the recipe key from a file-first `submit()`, or `null` on reattach).
@@ -221,13 +236,16 @@ export class Handle {
221
236
  if (isFanoutStatus(finalStatus)) {
222
237
  return projectMultiJobToRunResult(this.workflowId, finalStatus, jobDownloads, new Map(), downloader);
223
238
  }
224
- // A fluent `files([...]).merge(...)` combine — project ONLY the merged
225
- // output, filtering the `src_*` passthrough plumbing (which re-exposes the
226
- // raw inputs). Matches MergedRecipe.run()'s `ref === 'merge'` filter so a
239
+ // A fluent `files([...]).merge(...)` combine — project ONLY the terminal
240
+ // deliverable, filtering the `src_*` passthrough plumbing (which re-exposes
241
+ // the raw inputs). Matches MergedRecipe.run()'s terminal-output filter so a
227
242
  // submitted/reattached merge handle never surfaces the input artifacts
228
243
  // alongside the combined output (codex c1).
229
244
  if (isMergeStatus(finalStatus)) {
230
- const mergeDownloads = jobDownloads.filter((d) => d.ref === 'merge');
245
+ // Post-merge steps (PIiUit28) lower into the downstream `_POST_STEP_JOB_REF`
246
+ // job, which is then the deliverable; otherwise the `merge` job is.
247
+ const mergeOutputRef = terminalOutputRef(jobDownloads, 'merge');
248
+ const mergeDownloads = jobDownloads.filter((d) => d.ref === mergeOutputRef);
231
249
  return projectDownloadsToRunResult(this.workflowId, finalStatus, mergeDownloads, null, downloader);
232
250
  }
233
251
  // A fluent `files([...]).archive(...)` bundle — project ONLY the archive
@@ -237,14 +255,25 @@ export class Handle {
237
255
  const archiveDownloads = jobDownloads.filter((d) => d.ref === 'archive');
238
256
  return projectDownloadsToRunResult(this.workflowId, finalStatus, archiveDownloads, null, downloader);
239
257
  }
240
- // A fluent `file(...).watermark(overlay)` — project ONLY the watermark
241
- // output, filtering the `src_*` (base/overlay) passthrough plumbing. Matches
242
- // WatermarkedRecipe.run()'s `ref === 'watermark'` filter so a
258
+ // A fluent `file(...).watermark(overlay)` — project ONLY the terminal
259
+ // deliverable, filtering the `src_*` (base/overlay) passthrough plumbing.
260
+ // Matches WatermarkedRecipe.run()'s terminal-output filter so a
243
261
  // submitted/reattached watermark handle never surfaces the raw inputs.
244
262
  if (isWatermarkStatus(finalStatus)) {
245
- const watermarkDownloads = jobDownloads.filter((d) => d.ref === 'watermark');
263
+ const watermarkOutputRef = terminalOutputRef(jobDownloads, 'watermark');
264
+ const watermarkDownloads = jobDownloads.filter((d) => d.ref === watermarkOutputRef);
246
265
  return projectDownloadsToRunResult(this.workflowId, finalStatus, watermarkDownloads, null, downloader);
247
266
  }
267
+ // A single-input `sole_op` chain — e.g. `.textWatermark('x').compress()`
268
+ // lowered to a `text_watermark` job + downstream `post` job (IQc01rj0).
269
+ // Project ONLY the terminal deliverable, filtering the intermediate sole_op
270
+ // artifact. The recipe key is preserved (unlike the multi-input branches):
271
+ // this is the single-file path with a terminal-ref filter.
272
+ if (isSoleOpChainStatus(finalStatus)) {
273
+ const soleOpRef = soleOpChainDeliverableRef(finalStatus);
274
+ const soleOpDownloads = jobDownloads.filter((d) => d.ref === soleOpRef);
275
+ return projectDownloadsToRunResult(this.workflowId, finalStatus, soleOpDownloads, this.#key, downloader);
276
+ }
248
277
  return projectDownloadsToRunResult(this.workflowId, finalStatus, jobDownloads, this.#key, downloader);
249
278
  }
250
279
  /**
@@ -3,7 +3,7 @@ export { parseSseStream } from './sse.js';
3
3
  export type { CreditsUsageOptions, ListWorkflowsOptions, GetSchemaOptions, GetSchemaResult, CapabilitiesSnapshot, PreflightClipError, PreflightClipsResult, ProbeWaitOptions, ProbeWaitResult, GislClientConfig, GislSseEvent, GislSseParseFailure, UploadOptions, WaitOptions, WorkflowCreatePayload, OperationDef, WorkflowSourcePayload, MultiInputSourcePayload, UploadSourcePayload, JobOutputSourcePayload, ExternalImportSourcePayload, ConnectionSourcePayload, JobInputV2Payload, JobDefinitionPayload, ExternalDestinationPayload, DeliveryPayload, DeliveryModePayload, DeliveryBundleFormatPayload, DeliverySelectionPayload, DeliverySelectionTypePayload, DeliveryOutputRefPayload, WorkflowProcessingPayload, ProcessingClassHintPayload, MultipartCheckpointState, _Sdk3HandCodedUploadedPart, _Sdk3HandCodedMultipartStatusResult, _Sdk3HandCodedPresignedPart, _Sdk3HandCodedPresignPartsResult, _Sdk3HandCodedKeepaliveResult, } from './types.js';
4
4
  export { uploadSource, jobOutputSource, externalImportSource, connectionSource, } from './types.js';
5
5
  export type { GislConfigErrorMetadata } from './errors.js';
6
- export { GislError, GislApiError, GislValidationError, GislBalanceExhaustedError, GislTierRestrictedError, GislFeatureTierRestrictedError, GislFeatureNotAvailableError, GislWorkflowExpiredError, GislProbePendingError, GislAuthError, GislUploadCapExceededError, GislMultipartPartError, GislMultipartPartCountError, GislMultipartSessionNotFoundError, GislMultipartSessionOwnershipError, GislMultipartSessionAuthRequiredError, GislTimeoutError, GislAbortError, GislNetworkError, GislConfigError, GislMissingCredentialsError, GislFeatureRequiresAuthError, GislUndeclaredAssetError, GislUnusedAssetError, GislPerInputOptionsNotSupportedError, GislChainCardinalityMismatchError, GislBundleAlreadyArchivedError, GislNoSuchKeyError, GislSinkError, GislItemFailedError, GislResultNotReadyError, } from './errors.js';
6
+ export { GislError, GislApiError, GislValidationError, GislBalanceExhaustedError, GislLongFormConcurrencyError, GislTierRestrictedError, GislFeatureTierRestrictedError, GislFeatureNotAvailableError, GislWorkflowExpiredError, GislProbePendingError, GislAuthError, GislUploadCapExceededError, GislMultipartPartError, GislMultipartPartCountError, GislMultipartSessionNotFoundError, GislMultipartSessionOwnershipError, GislMultipartSessionAuthRequiredError, GislTimeoutError, GislFanOutTimeoutError, GislAbortError, GislNetworkError, GislConfigError, GislMissingCredentialsError, GislFeatureRequiresAuthError, GislUndeclaredAssetError, GislUnusedAssetError, GislPerInputOptionsNotSupportedError, GislChainCardinalityMismatchError, GislBundleAlreadyArchivedError, GislNoSuchKeyError, GislSinkError, GislItemFailedError, GislResultNotReadyError, } from './errors.js';
7
7
  export type { GislApiErrorOptions, GislUploadCapKind } from './errors.js';
8
8
  export type { ErrorCategory } from './generated/sdk_spec/errors.js';
9
9
  export { RunResult } from './file-first.js';
@@ -20,20 +20,20 @@ export { BatchRecipe } from './file-first.js';
20
20
  export { Handle, StatusSnapshot } from './handle.js';
21
21
  export { gisl, create } from './gisl.js';
22
22
  export type { GislCreateOptions, Environment, ErgonomicClient, SingleInputOperationType, MultiInputOperationType, } from './gisl.js';
23
- export { presetDefaults, PresetDefaults, type PresetMedia, type PresetOp, type AnyPresetOptions, ImageCompressPresetOptions, type ImageCompressPresetOptionsInput, AudioCompressPresetOptions, type AudioCompressPresetOptionsInput, VideoCompressPresetOptions, type VideoCompressPresetOptionsInput, DocumentPdfCompressPresetOptions, type DocumentPdfCompressPresetOptionsInput, DocumentOfficeCompressPresetOptions, type DocumentOfficeCompressPresetOptionsInput, DocumentOdfCompressPresetOptions, type DocumentOdfCompressPresetOptionsInput, DocumentEpubCompressPresetOptions, type DocumentEpubCompressPresetOptionsInput, OptimizeFor, ImageMetadataPolicy, ImageFormat, VideoCodec, VideoPreset, VideoFit, AudioBitrate, AudioCodec, AudioSampleRate, PdfProfile, PdfColorspace, } from './ergonomic/presets/index.js';
23
+ export { presetDefaults, PresetDefaults, type PresetMedia, type PresetOp, type AnyPresetOptions, ImageCompressPresetOptions, type ImageCompressPresetOptionsInput, AudioCompressPresetOptions, type AudioCompressPresetOptionsInput, VideoCompressPresetOptions, type VideoCompressPresetOptionsInput, DocumentOfficeCompressPresetOptions, type DocumentOfficeCompressPresetOptionsInput, DocumentOdfCompressPresetOptions, type DocumentOdfCompressPresetOptionsInput, DocumentEpubCompressPresetOptions, type DocumentEpubCompressPresetOptionsInput, OptimizeFor, ImageMetadataPolicy, ImageFormat, VideoCodec, VideoPreset, VideoFit, AudioBitrate, AudioCodec, AudioSampleRate, } from './ergonomic/presets/index.js';
24
24
  export { OperationBuilder, MapEachBuilder } from './builder.js';
25
25
  export { MergeBuilder, asset, handle, clip } from './merge.js';
26
26
  export type { Asset, ClipEntry, ClipOptions, MergeMediaKind, MergeOptions, SequenceEntry, } from './merge.js';
27
27
  export type { Artifact, ArtifactRef, JobBreakdown, OperationBreakdown, ProcessingProgressEvent, ProgressEvent, ResolvedOptions, ResolvedOptionsSources, Result, RunOptions, SubmitOptions, UploadProgressEvent, } from './builder.js';
28
28
  export { PRESET_VERSION, resolveCompressOptions } from './ergonomic/preset_resolver.js';
29
29
  export type { ResolveCompressOptionsInput, ResolveCompressOptionsOutput, } from './ergonomic/preset_resolver.js';
30
- export type { AccountLimits, AccountLimitsLimits, AccountLimitEntry, AudioWatermarkDecodeRequest, AudioWatermarkDecodeResponse, ContactRequest, CreditsBalanceResponse, CreditsUsageResponse, CreditTransaction, ExternalImportCreatedResponse, ExternalImportRequest, LoginUserRequest, LoginUser200ResponseData, LoginUser200ResponseDataUser, WorkflowCancelResponse, WorkflowResumeResponse, WorkflowPausedDetail, WorkflowPausedDetailLinks, UploadResponse, UploadConstraintsApplied, UploadProbeResponse, UploadProbeMediaMetadata, MultipartInitiateRequestMetadataHint, WorkflowCreateResponse, WorkflowStatusResponse, WorkflowListResponse, WorkflowSummary, WorkflowDownloadResponse, MetadataResponse, MetadataResponseDimensions, MetadataResponseExif, MetadataResponseExifGps, OperationsSchemaResponse, OperationCapability, OutputProperties, ImageEncodeCapabilities, OperationSchemaDefinition, MimeGroupSchema, OptionSchema, PerValueAvailabilityEntry, PerRoleCardinalityEntry, RetryResponse, JobDownload, OperationDownload, DownloadBundle, WebhookPayload, WebhookOperationContext, JobResponse, OperationResponse, OperationResult, OperationResultMetrics, ExternalDestination, Delivery, DeliveryPlan, DeliveryPlanOutput, WorkflowProcessing, ProcessingPlan, ProcessingPlanJob, WorkflowEdge, WorkflowWarning, JobInputV2, WorkflowSource, UploadSource, JobOutputSource, ConnectionSource, ExternalImportToken, BalanceExhaustedResponse, BalanceExhaustedResponseAllOfLinks, TierRestrictionResponse, FeatureTierRestrictedResponse, FeatureNotAvailableResponse, FeatureViolation, WorkflowExpiredResponse, ProbePendingResponse, AuthErrorResponse, } from '@giveitsmaller/contracts/openapi';
30
+ export type { AccountLimits, AccountLimitsLimits, AccountLimitEntry, AudioWatermarkDecodeRequest, AudioWatermarkDecodeResponse, ContactRequest, CreditsBalanceResponse, CreditsUsageResponse, CreditTransaction, ExternalImportCreatedResponse, ExternalImportRequest, LoginUserRequest, LoginUser200ResponseData, LoginUser200ResponseDataUser, WorkflowCancelResponse, WorkflowResumeResponse, WorkflowPausedDetail, WorkflowPausedDetailLinks, UploadResponse, UploadConstraintsApplied, UploadProbeResponse, UploadProbeMediaMetadata, MultipartInitiateRequestMetadataHint, WorkflowCreateResponse, WorkflowStatusResponse, WorkflowListResponse, WorkflowSummary, WorkflowDownloadResponse, MetadataResponse, MetadataResponseDimensions, MetadataResponseExif, MetadataResponseExifGps, OperationsSchemaResponse, OperationCapability, OutputProperties, ImageEncodeCapabilities, OperationSchemaDefinition, MimeGroupSchema, OptionSchema, PerValueAvailabilityEntry, PerRoleCardinalityEntry, RetryResponse, JobDownload, OperationDownload, DownloadBundle, WebhookPayload, WebhookOperationContext, JobResponse, OperationResponse, OperationResult, OperationResultMetrics, ExternalDestination, Delivery, DeliveryPlan, DeliveryPlanOutput, WorkflowProcessing, ProcessingPlan, ProcessingPlanJob, WorkflowEdge, WorkflowWarning, JobInputV2, WorkflowSource, UploadSource, JobOutputSource, ConnectionSource, ExternalImportToken, BalanceExhaustedResponse, BalanceExhaustedResponseAllOfLinks, LongFormConcurrencyLimitResponse, LongFormConcurrencyLimitResponseAllOfLinks, TierRestrictionResponse, FeatureTierRestrictedResponse, FeatureNotAvailableResponse, FeatureViolation, WorkflowExpiredResponse, ProbePendingResponse, AuthErrorResponse, } from '@giveitsmaller/contracts/openapi';
31
31
  export { AudioWatermarkDecodeRequestMethodHintEnum, AudioWatermarkDecodeResponseMethodEnum, OperationInputModel, ExternalImportRequestProviderHintEnum, ContactSubject, CreditTransactionSourceBucket, UploadProbeStatus, UploadProbeProcessingClass, WorkflowCancelBillingEffect, WorkflowPauseRequiredAction, WorkflowStatus, WarningType, WorkflowWarningSeverity, OperationType, SseEventType, CallbackEventType, OperationStatus, JobStatus, JobInputV2RoleEnum, AuthErrorType, TierRestrictionKind, BalanceExhaustedResponseRequiredActionEnum, ProcessingClassReason, DeliveryPlanReason, UserTier, ProcessingClass, } from '@giveitsmaller/contracts/openapi';
32
32
  export type { SseOperationProgressData, SseOperationCompletedData, SseOperationFailedData, SseJobCompletedData, SseJobFailedData, SseWorkflowTerminalData, } from '@giveitsmaller/contracts/openapi';
33
33
  export type { MultiOutputCompletion, PageIndexed, PositionIndexed, Unindexed, } from '@giveitsmaller/contracts/asyncapi';
34
34
  import type { MultiOutputCompletion as _MultiOutputCompletion } from '@giveitsmaller/contracts/asyncapi';
35
35
  export type OperationResultOutputEntry = _MultiOutputCompletion['outputs'][number];
36
- export type { CompressImageOptions, CompressImageJpegOptions, CompressImagePngOptions, CompressImageAvifOptions, CompressVideoOptions, CompressAudioOptions, CompressDocumentPdfOptions, CompressDocumentOfficeOptions, CompressDocumentOdfOptions, CompressDocumentEpubOptions, ThumbnailImageOptions, ThumbnailVideoOptions, ThumbnailDocumentOptions, TransformImageOptions, TransformImageGifOptions, TransformVideoOptions, TransformDocumentPdfOptions, ConvertImageOptions, ConvertVideoOptions, ConvertAudioOptions, ConvertDocumentPdfOptions, MergeImageOptions, MergeVideoOptions, MergeVideoPerInputOptions, MergeAudioOptions, MergeAudioPerInputOptions, ArchiveOptions, ImageWatermarkImageOptions, ImageWatermarkImageGifOptions, TextWatermarkImageOptions, CustomLumaVideoOptions, AudioOverlayAudioOptions, AudioOverlayVideoOptions, AudioWatermarkAudioOptions, AudioWatermarkVideoOptions, AudioToVideoAudioOptions, VideoWatermarkVideoOptions, VideoTextWatermarkVideoOptions, SplitImageGifOptions, SplitDocumentPdfOptions, SplitAudioOptions, SplitVideoOptions, } from '@giveitsmaller/contracts/operations';
36
+ export type { CompressImageOptions, CompressImageJpegOptions, CompressImagePngOptions, CompressImageAvifOptions, CompressVideoOptions, CompressAudioOptions, CompressDocumentOfficeOptions, CompressDocumentOdfOptions, CompressDocumentEpubOptions, ThumbnailImageOptions, ThumbnailVideoOptions, ThumbnailDocumentOptions, TransformImageOptions, TransformImageGifOptions, TransformVideoOptions, TransformDocumentPdfOptions, ConvertImageOptions, ConvertVideoOptions, ConvertAudioOptions, ConvertDocumentPdfOptions, MergeImageOptions, MergeVideoOptions, MergeVideoPerInputOptions, MergeAudioOptions, MergeAudioPerInputOptions, ArchiveOptions, ImageWatermarkImageOptions, ImageWatermarkImageGifOptions, TextWatermarkImageOptions, CustomLumaVideoOptions, AudioOverlayAudioOptions, AudioOverlayVideoOptions, AudioWatermarkAudioOptions, AudioWatermarkVideoOptions, AudioToVideoAudioOptions, VideoWatermarkVideoOptions, VideoTextWatermarkVideoOptions, SplitImageGifOptions, SplitDocumentPdfOptions, SplitAudioOptions, SplitVideoOptions, } from '@giveitsmaller/contracts/operations';
37
37
  export { ImageWatermarkImageAnchor, ImageWatermarkImageGifAnchor, TextWatermarkImageAnchor, TextWatermarkImageFontFamily, TextWatermarkImageWatermarkMode, AudioOverlayAudioMode, AudioOverlayVideoMode, AudioOverlayVideoNoAudioTrackBehaviour, AudioWatermarkAudioMethod, AudioWatermarkAudioRobustness, AudioWatermarkAudioDensity, AudioWatermarkVideoMethod, AudioWatermarkVideoRobustness, AudioWatermarkVideoDensity, AudioToVideoAudioOutputResolution, AudioToVideoAudioImageFit, AudioToVideoAudioOutputFormat, VideoWatermarkVideoAnchor, VideoTextWatermarkVideoFontFamily, VideoTextWatermarkVideoWatermarkMode, VideoTextWatermarkVideoAnchor, SplitImageGifOutputFormat, SplitDocumentPdfMode, SplitAudioMode, SplitAudioPrecision, SplitVideoMode, SplitVideoPrecision, } from '@giveitsmaller/contracts/operations';
38
38
  export { archiveMetadata, audioOverlayMetadata, audioWatermarkMetadata, compressMetadata, convertMetadata, customLumaMetadata, imageWatermarkMetadata, mergeMetadata, textWatermarkMetadata, thumbnailMetadata, audioToVideoMetadata, videoWatermarkMetadata, videoTextWatermarkMetadata, splitMetadata, transformMetadata, } from '@giveitsmaller/contracts/operations';
39
39
  export type { ConvertOptions, ThumbnailOptions, TransformOptions, TextWatermarkOptions, WatermarkOptions, WatermarkOverlay, WatermarkAnchor, } from './ergonomic/option_types.js';
@@ -9,9 +9,12 @@ export { GislClient, DEFAULT_MULTIPART_FIRST_CHUNK_SIZE } from './client.js';
9
9
  export { parseSseStream } from './sse.js';
10
10
  export { uploadSource, jobOutputSource, externalImportSource, connectionSource, } from './types.js';
11
11
  // Errors
12
- export { GislError, GislApiError, GislValidationError, GislBalanceExhaustedError, GislTierRestrictedError, GislFeatureTierRestrictedError, GislFeatureNotAvailableError, GislWorkflowExpiredError, GislProbePendingError, GislAuthError, GislUploadCapExceededError, GislMultipartPartError, GislMultipartPartCountError,
12
+ export { GislError, GislApiError, GislValidationError, GislBalanceExhaustedError, GislLongFormConcurrencyError, GislTierRestrictedError, GislFeatureTierRestrictedError, GislFeatureNotAvailableError, GislWorkflowExpiredError, GislProbePendingError, GislAuthError, GislUploadCapExceededError, GislMultipartPartError, GislMultipartPartCountError,
13
13
  // SDK-3 (Wb6ebOMM) — typed errors for the 3 resume-support endpoints.
14
- GislMultipartSessionNotFoundError, GislMultipartSessionOwnershipError, GislMultipartSessionAuthRequiredError, GislTimeoutError, GislAbortError,
14
+ GislMultipartSessionNotFoundError, GislMultipartSessionOwnershipError, GislMultipartSessionAuthRequiredError, GislTimeoutError,
15
+ // 4G4FaA9X — mapEach fan-out timed out mid-batch; carries the completed
16
+ // child ids + parent id so the caller can recover without a whole-batch re-run.
17
+ GislFanOutTimeoutError, GislAbortError,
15
18
  // FF2b / tywwynmN — transport-level failure (mirrors PHP GislNetworkError);
16
19
  // raised by the file-first HttpDownloader when an output URL cannot be read.
17
20
  GislNetworkError,
@@ -77,7 +80,7 @@ export { gisl, create } from './gisl.js';
77
80
  // Ergonomic preset defaults (T4a / VhIj4S7T) — typed leaf DTOs + immutable
78
81
  // `PresetDefaults` builder + `presetDefaults()` factory + ergonomic enum
79
82
  // re-exports. Resolver wiring (T4b) consumes `PresetDefaults.cellFor()`.
80
- export { presetDefaults, PresetDefaults, ImageCompressPresetOptions, AudioCompressPresetOptions, VideoCompressPresetOptions, DocumentPdfCompressPresetOptions, DocumentOfficeCompressPresetOptions, DocumentOdfCompressPresetOptions, DocumentEpubCompressPresetOptions, OptimizeFor, ImageMetadataPolicy, ImageFormat, VideoCodec, VideoPreset, VideoFit, AudioBitrate, AudioCodec, AudioSampleRate, PdfProfile, PdfColorspace, } from './ergonomic/presets/index.js';
83
+ export { presetDefaults, PresetDefaults, ImageCompressPresetOptions, AudioCompressPresetOptions, VideoCompressPresetOptions, DocumentOfficeCompressPresetOptions, DocumentOdfCompressPresetOptions, DocumentEpubCompressPresetOptions, OptimizeFor, ImageMetadataPolicy, ImageFormat, VideoCodec, VideoPreset, VideoFit, AudioBitrate, AudioCodec, AudioSampleRate, } from './ergonomic/presets/index.js';
81
84
  // Operation-builder surface (T2 / xVDTIm8C) — `client.compress/convert/thumbnail`
82
85
  // returns an `OperationBuilder`; `.run()` projects to a flat `Result` /
83
86
  // `.submit({webhook})` returns a `Handle`. Progress events are the
package/dist/merge.d.ts CHANGED
@@ -103,6 +103,29 @@ export interface MergeOptions {
103
103
  readonly preset?: string;
104
104
  /** Video output dimensions `WxH` (e.g. `"1920x1080"`); omit to inherit from inputs. Video merge only. */
105
105
  readonly targetResolution?: string;
106
+ /**
107
+ * Target output size (bytes, or a `'50MB'`-style string). Lowered to wire
108
+ * `target_size_bytes`, and the SDK also sets `encoding_mode: 'target_size'` alongside
109
+ * it. Video merge only.
110
+ *
111
+ * **UNITS ARE DECIMAL HERE (1 KB = 1000), UNLIKE `compress`.** `compress`'s
112
+ * `targetSize` parses the same strings as BINARY (1 KB = 1024), so `'50MB'` means
113
+ * 50,000,000 bytes on a merge and 52,428,800 bytes on a compress. That divergence is
114
+ * NOT deliberate — it contradicts the pinned convention that every human-readable
115
+ * size string in this SDK is binary — and it has a sharp edge: the contract floor for
116
+ * `target_size_bytes` is 1 MiB (1,048,576), so `'1MB'` here resolves to 1,000,000 and
117
+ * is rejected as below the minimum. Prefer an explicit byte count until this is
118
+ * reconciled. Tracked by `YOCz0i74`; changing it moves bytes for existing callers, so
119
+ * it is a deliberate decision rather than a silent correction.
120
+ *
121
+ * **NOT AVAILABLE FOR LONG INPUTS.** Merges whose summed input duration routes to
122
+ * the long-form Fargate path reject both keys — that path is single-pass-CRF by
123
+ * construction and two-pass target-size is unbuilt. The request fails during
124
+ * execution, and the SDK cannot warn earlier: the routing decision is made
125
+ * server-side at create-plan time, so there is nothing here to check it against.
126
+ * Short-form merges honour it normally. Tracked by `zJN6XIi5`, blocked on a
127
+ * contract that can express per-execution-path availability.
128
+ */
106
129
  readonly targetSize?: string | number;
107
130
  readonly transitionDuration?: number;
108
131
  readonly fps?: number;