@giveitsmaller/sdk 0.4.0 → 0.7.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 (50) hide show
  1. package/dist/_audit.js +67 -0
  2. package/dist/builder.d.ts +406 -0
  3. package/dist/builder.js +706 -0
  4. package/dist/client.d.ts +96 -2
  5. package/dist/client.js +968 -33
  6. package/dist/credentials.d.ts +61 -0
  7. package/dist/credentials.js +200 -0
  8. package/dist/ergonomic/preset_resolver.d.ts +75 -0
  9. package/dist/ergonomic/preset_resolver.js +568 -0
  10. package/dist/ergonomic/presets/_translate.d.ts +11 -0
  11. package/dist/ergonomic/presets/_translate.js +35 -0
  12. package/dist/ergonomic/presets/audio_compress.d.ts +16 -0
  13. package/dist/ergonomic/presets/audio_compress.js +45 -0
  14. package/dist/ergonomic/presets/document_epub_compress.d.ts +14 -0
  15. package/dist/ergonomic/presets/document_epub_compress.js +34 -0
  16. package/dist/ergonomic/presets/document_odf_compress.d.ts +14 -0
  17. package/dist/ergonomic/presets/document_odf_compress.js +34 -0
  18. package/dist/ergonomic/presets/document_office_compress.d.ts +16 -0
  19. package/dist/ergonomic/presets/document_office_compress.js +40 -0
  20. package/dist/ergonomic/presets/document_pdf_compress.d.ts +14 -0
  21. package/dist/ergonomic/presets/document_pdf_compress.js +35 -0
  22. package/dist/ergonomic/presets/image_compress.d.ts +43 -0
  23. package/dist/ergonomic/presets/image_compress.js +95 -0
  24. package/dist/ergonomic/presets/index.d.ts +77 -0
  25. package/dist/ergonomic/presets/index.js +216 -0
  26. package/dist/ergonomic/presets/video_compress.d.ts +30 -0
  27. package/dist/ergonomic/presets/video_compress.js +83 -0
  28. package/dist/errors.d.ts +251 -1
  29. package/dist/errors.js +268 -0
  30. package/dist/generated/sdk_spec/enums.d.ts +195 -0
  31. package/dist/generated/sdk_spec/enums.js +127 -0
  32. package/dist/generated/sdk_spec/errors.d.ts +16 -0
  33. package/dist/generated/sdk_spec/errors.js +473 -0
  34. package/dist/generated/sdk_spec/index.d.ts +4 -0
  35. package/dist/generated/sdk_spec/index.js +7 -0
  36. package/dist/generated/sdk_spec/presets.d.ts +6 -0
  37. package/dist/generated/sdk_spec/presets.js +157 -0
  38. package/dist/generated/sdk_spec/version.d.ts +3 -0
  39. package/dist/generated/sdk_spec/version.js +6 -0
  40. package/dist/gisl.d.ts +112 -0
  41. package/dist/gisl.js +266 -0
  42. package/dist/index.d.ts +17 -7
  43. package/dist/index.js +33 -3
  44. package/dist/merge.d.ts +142 -0
  45. package/dist/merge.js +411 -0
  46. package/dist/sse.d.ts +20 -1
  47. package/dist/sse.js +62 -3
  48. package/dist/types.d.ts +144 -14
  49. package/dist/types.js +18 -0
  50. package/package.json +2 -2
@@ -0,0 +1,216 @@
1
+ // T4a — PresetDefaults immutable builder + presetDefaults() factory.
2
+ //
3
+ // Implements the user-facing path for layered preset configuration:
4
+ //
5
+ // const defaults = presetDefaults()
6
+ // .imageCompress(OptimizeFor.Size, { quality: 75 })
7
+ // .videoCompress(OptimizeFor.Quality);
8
+ //
9
+ // const client = await gisl.create({ presetDefaults: defaults });
10
+ //
11
+ // `T4a` ships only the typed slot and the builder semantics — the
12
+ // resolver (T4b) reads `defaults.cellFor(media, op, level)` and merges
13
+ // shipped defaults + this user delta + per-call overrides at workflow-
14
+ // create time.
15
+ //
16
+ // **Semantics**
17
+ // - `cellFor(media, op, level)` returns the USER-SUPPLIED DELTA stored
18
+ // by the matching `.imageCompress(level, input)` call, or `undefined`
19
+ // if no such delta was registered. It does NOT return shipped defaults
20
+ // — those live on the leaf class (`*.shippedDefaultsFor(level)`).
21
+ // - Per-cell methods are immutable: each returns a fresh `PresetDefaults`
22
+ // carrying the original entries plus the new (cell, level) registration.
23
+ // Calling the same method twice on the same instance yields two
24
+ // distinct objects.
25
+ // - Calling `.imageCompress(level)` with no input registers an empty
26
+ // delta — the resolver will see "this cell asked for `level` with no
27
+ // overrides" and apply shipped defaults verbatim.
28
+ import { ImageCompressPresetOptions, } from './image_compress.js';
29
+ import { AudioCompressPresetOptions, } from './audio_compress.js';
30
+ import { VideoCompressPresetOptions, } from './video_compress.js';
31
+ import { DocumentPdfCompressPresetOptions, } from './document_pdf_compress.js';
32
+ import { DocumentOfficeCompressPresetOptions, } from './document_office_compress.js';
33
+ import { DocumentOdfCompressPresetOptions, } from './document_odf_compress.js';
34
+ import { DocumentEpubCompressPresetOptions, } from './document_epub_compress.js';
35
+ // Re-export everything callers need from this module's root.
36
+ export { ImageCompressPresetOptions, } from './image_compress.js';
37
+ export { AudioCompressPresetOptions, } from './audio_compress.js';
38
+ export { VideoCompressPresetOptions, } from './video_compress.js';
39
+ export { DocumentPdfCompressPresetOptions, } from './document_pdf_compress.js';
40
+ export { DocumentOfficeCompressPresetOptions, } from './document_office_compress.js';
41
+ export { DocumentOdfCompressPresetOptions, } from './document_odf_compress.js';
42
+ export { DocumentEpubCompressPresetOptions, } from './document_epub_compress.js';
43
+ // Re-export ergonomic enums for callers (single canonical path).
44
+ export { OptimizeFor, ImageMode, ImageFit, ImageMetadataPolicy, IccProfilePolicy, ImageFormat, VideoCodec, VideoPreset, VideoFit, AudioBitrate, AudioCodec, AudioSampleRate, PdfProfile, PdfColorspace, } from '../../generated/sdk_spec/enums.js';
45
+ function cellKeyOf(media, op) {
46
+ return `${media}_${op}`;
47
+ }
48
+ /**
49
+ * Per-cell field-merge: parent fields ⊕ child fields where defined.
50
+ * Re-construct the leaf DTO via the matching `<LeafClass>.from(merged)`
51
+ * call so the result is a freshly-frozen `*PresetOptions` instance —
52
+ * NOT a mutated reference into either input. Used by
53
+ * {@link PresetDefaults.merge} when both parent and child registered
54
+ * the same `(cellKey, level)` tuple.
55
+ *
56
+ * `definedFieldsOf` filters undefined values out of each instance
57
+ * BEFORE the merge: with TS `useDefineForClassFields` (the ES2022
58
+ * default), `readonly mode?: ImageMode` declarations initialise the
59
+ * field as an enumerable own property with value `undefined` BEFORE
60
+ * the ctor body runs. A naive `Object.assign({}, parent, child)`
61
+ * therefore lets child's `undefined` overwrite parent's defined value
62
+ * — caught by CI on PR #125 first run. Filter-then-spread restores
63
+ * the documented merge-not-replace semantics.
64
+ *
65
+ * @internal
66
+ */
67
+ function definedFieldsOf(opts) {
68
+ const out = {};
69
+ for (const key of Object.keys(opts)) {
70
+ const value = opts[key];
71
+ if (value !== undefined)
72
+ out[key] = value;
73
+ }
74
+ return out;
75
+ }
76
+ function mergePresetOptions(cellKey, parentOpts, childOpts) {
77
+ // Child fields win on overlap; parent fills the remaining gaps.
78
+ // `definedFieldsOf` strips undefined-valued slots that TS class
79
+ // field declarations create even when the ctor body skipped the
80
+ // assignment (see helper docblock).
81
+ const mergedFields = {
82
+ ...definedFieldsOf(parentOpts),
83
+ ...definedFieldsOf(childOpts),
84
+ };
85
+ switch (cellKey) {
86
+ case 'image_compress':
87
+ return ImageCompressPresetOptions.from(mergedFields);
88
+ case 'audio_compress':
89
+ return AudioCompressPresetOptions.from(mergedFields);
90
+ case 'video_compress':
91
+ return VideoCompressPresetOptions.from(mergedFields);
92
+ case 'document_pdf_compress':
93
+ return DocumentPdfCompressPresetOptions.from(mergedFields);
94
+ case 'document_office_compress':
95
+ return DocumentOfficeCompressPresetOptions.from(mergedFields);
96
+ case 'document_odf_compress':
97
+ return DocumentOdfCompressPresetOptions.from(mergedFields);
98
+ case 'document_epub_compress':
99
+ return DocumentEpubCompressPresetOptions.from(mergedFields);
100
+ }
101
+ }
102
+ /**
103
+ * Append `(level, options)` into a fresh map under `cellKey`, returning
104
+ * a new outer map. Both layers stay immutable — callers' references to
105
+ * the previous PresetDefaults remain unchanged.
106
+ */
107
+ function withCellEntry(prev, cellKey, level, options) {
108
+ const next = new Map(prev);
109
+ const prevEntries = prev.get(cellKey);
110
+ const nextEntries = new Map(prevEntries ?? []);
111
+ nextEntries.set(level, options);
112
+ next.set(cellKey, nextEntries);
113
+ return next;
114
+ }
115
+ export class PresetDefaults {
116
+ cells;
117
+ constructor(cells) {
118
+ this.cells = cells;
119
+ Object.freeze(this);
120
+ }
121
+ /** Empty builder — entry point for `presetDefaults()`. @internal */
122
+ static _empty() {
123
+ return new PresetDefaults(new Map());
124
+ }
125
+ /**
126
+ * Deep-merge two {@link PresetDefaults} into a new instance (T4c —
127
+ * `ULAlOP6j`). Used by `withPresetDefaults` to stack scoped derives:
128
+ * `client.withPresetDefaults(a).withPresetDefaults(b)` produces a
129
+ * scoped layer equivalent to `merge(a, b)` — `b`'s per-cell fields
130
+ * override `a`'s where defined; `a`'s fields fill gaps.
131
+ *
132
+ * Per-cell semantics (codex r2 #5 — scalar-leaf merge):
133
+ * - If a `(cellKey, level)` entry is present in EITHER only, take it
134
+ * verbatim.
135
+ * - If present in both, merge the per-cell `*Input` shapes via
136
+ * `Object.assign({}, parentInput, childInput)` and re-construct
137
+ * the leaf DTO. Every cell-DTO field is a scalar (primitive,
138
+ * enum-string, or `string | number` for `targetSize`) — shallow
139
+ * merge gives the correct field-wise override.
140
+ *
141
+ * Parent and child instances are unaffected.
142
+ */
143
+ static merge(parent, child) {
144
+ const merged = new Map();
145
+ // Seed with a clone of parent's entries (one inner Map per cellKey
146
+ // so child writes don't bleed back into parent's frozen structure).
147
+ for (const [cellKey, entries] of parent.cells) {
148
+ merged.set(cellKey, new Map(entries));
149
+ }
150
+ // Overlay child entries. Same (cellKey, level) → field-merge;
151
+ // child-only → take verbatim.
152
+ for (const [cellKey, childEntries] of child.cells) {
153
+ const target = merged.get(cellKey);
154
+ if (target === undefined) {
155
+ merged.set(cellKey, new Map(childEntries));
156
+ continue;
157
+ }
158
+ for (const [level, childOpts] of childEntries) {
159
+ const parentOpts = target.get(level);
160
+ if (parentOpts === undefined) {
161
+ target.set(level, childOpts);
162
+ continue;
163
+ }
164
+ target.set(level, mergePresetOptions(cellKey, parentOpts, childOpts));
165
+ }
166
+ }
167
+ return new PresetDefaults(merged);
168
+ }
169
+ /** Register a (level, delta) on the image-compress cell. Immutable. */
170
+ imageCompress(level, input = {}) {
171
+ return new PresetDefaults(withCellEntry(this.cells, 'image_compress', level, ImageCompressPresetOptions.from(input)));
172
+ }
173
+ /** Register a (level, delta) on the audio-compress cell. Immutable. */
174
+ audioCompress(level, input = {}) {
175
+ return new PresetDefaults(withCellEntry(this.cells, 'audio_compress', level, AudioCompressPresetOptions.from(input)));
176
+ }
177
+ /** Register a (level, delta) on the video-compress cell. Immutable. */
178
+ videoCompress(level, input = {}) {
179
+ return new PresetDefaults(withCellEntry(this.cells, 'video_compress', level, VideoCompressPresetOptions.from(input)));
180
+ }
181
+ /** Register a (level, delta) on the document-pdf-compress cell. Immutable. */
182
+ pdfCompress(level, input = {}) {
183
+ return new PresetDefaults(withCellEntry(this.cells, 'document_pdf_compress', level, DocumentPdfCompressPresetOptions.from(input)));
184
+ }
185
+ /** Register a (level, delta) on the document-office-compress cell. Immutable. */
186
+ officeCompress(level, input = {}) {
187
+ return new PresetDefaults(withCellEntry(this.cells, 'document_office_compress', level, DocumentOfficeCompressPresetOptions.from(input)));
188
+ }
189
+ /** Register a (level, delta) on the document-odf-compress cell. Immutable. */
190
+ odfCompress(level, input = {}) {
191
+ return new PresetDefaults(withCellEntry(this.cells, 'document_odf_compress', level, DocumentOdfCompressPresetOptions.from(input)));
192
+ }
193
+ /** Register a (level, delta) on the document-epub-compress cell. Immutable. */
194
+ epubCompress(level, input = {}) {
195
+ return new PresetDefaults(withCellEntry(this.cells, 'document_epub_compress', level, DocumentEpubCompressPresetOptions.from(input)));
196
+ }
197
+ /**
198
+ * Return the user-supplied delta registered for `(media, op, level)`,
199
+ * or `undefined` if none was registered.
200
+ *
201
+ * @internal — consumed by the T4b resolver. Not part of the public
202
+ * surface; the resolver imports it via the type-only re-export.
203
+ */
204
+ cellFor(media, op, level) {
205
+ const entries = this.cells.get(cellKeyOf(media, op));
206
+ return entries?.get(level);
207
+ }
208
+ }
209
+ /**
210
+ * Construct an empty {@link PresetDefaults} builder. Chain per-cell
211
+ * methods to register layered defaults; the resolver in T4b consumes
212
+ * the result via `cellFor(...)`.
213
+ */
214
+ export function presetDefaults() {
215
+ return PresetDefaults._empty();
216
+ }
@@ -0,0 +1,30 @@
1
+ import { VideoCodec, VideoPreset, VideoFit, AudioCodec, AudioBitrate, OptimizeFor } from '../../generated/sdk_spec/enums.js';
2
+ export interface VideoCompressPresetOptionsInput {
3
+ readonly codec?: VideoCodec;
4
+ readonly targetSize?: string | number;
5
+ readonly crf?: number;
6
+ readonly preset?: VideoPreset;
7
+ readonly width?: number;
8
+ readonly height?: number;
9
+ readonly fit?: VideoFit;
10
+ readonly fps?: number;
11
+ readonly faststart?: boolean;
12
+ readonly audioCodec?: AudioCodec;
13
+ readonly audioBitrate?: AudioBitrate;
14
+ }
15
+ export declare class VideoCompressPresetOptions {
16
+ readonly codec?: VideoCodec;
17
+ readonly targetSize?: string | number;
18
+ readonly crf?: number;
19
+ readonly preset?: VideoPreset;
20
+ readonly width?: number;
21
+ readonly height?: number;
22
+ readonly fit?: VideoFit;
23
+ readonly fps?: number;
24
+ readonly faststart?: boolean;
25
+ readonly audioCodec?: AudioCodec;
26
+ readonly audioBitrate?: AudioBitrate;
27
+ private constructor();
28
+ static from(input: VideoCompressPresetOptionsInput): VideoCompressPresetOptions;
29
+ static shippedDefaultsFor(level: OptimizeFor): VideoCompressPresetOptions;
30
+ }
@@ -0,0 +1,83 @@
1
+ // T4a — VideoCompressPresetOptions leaf DTO.
2
+ //
3
+ // Field set per ticket VhIj4S7T: video = 11 fields
4
+ // (codec, targetSize, crf, preset, width, height, fit, fps, faststart,
5
+ // audioCodec, audioBitrate).
6
+ // Deliberately excluded: encodingMode + targetSizeBytes (raw wire —
7
+ // replaced by ergonomic `targetSize: string|number` which the SDK derives
8
+ // at resolve time in T4b), trim_start/trim_end (per-call content selection).
9
+ //
10
+ // `targetSize` accepts `string` (e.g. "50MB") or `number` (bytes). The
11
+ // resolver in T4b converts to the wire `target_size_bytes` and sets
12
+ // `encoding_mode: target_size` accordingly.
13
+ import { shippedDefaultsFor as f3ShippedDefaultsFor } from '../../generated/sdk_spec/presets.js';
14
+ import { translateEnum } from './_translate.js';
15
+ export class VideoCompressPresetOptions {
16
+ codec;
17
+ targetSize;
18
+ crf;
19
+ preset;
20
+ width;
21
+ height;
22
+ fit;
23
+ fps;
24
+ faststart;
25
+ audioCodec;
26
+ audioBitrate;
27
+ constructor(input) {
28
+ if (input.codec !== undefined)
29
+ this.codec = input.codec;
30
+ if (input.targetSize !== undefined)
31
+ this.targetSize = input.targetSize;
32
+ if (input.crf !== undefined)
33
+ this.crf = input.crf;
34
+ if (input.preset !== undefined)
35
+ this.preset = input.preset;
36
+ if (input.width !== undefined)
37
+ this.width = input.width;
38
+ if (input.height !== undefined)
39
+ this.height = input.height;
40
+ if (input.fit !== undefined)
41
+ this.fit = input.fit;
42
+ if (input.fps !== undefined)
43
+ this.fps = input.fps;
44
+ if (input.faststart !== undefined)
45
+ this.faststart = input.faststart;
46
+ if (input.audioCodec !== undefined)
47
+ this.audioCodec = input.audioCodec;
48
+ if (input.audioBitrate !== undefined)
49
+ this.audioBitrate = input.audioBitrate;
50
+ Object.freeze(this);
51
+ }
52
+ static from(input) {
53
+ return new VideoCompressPresetOptions(input);
54
+ }
55
+ static shippedDefaultsFor(level) {
56
+ const cell = f3ShippedDefaultsFor('video_compress', level);
57
+ const input = {};
58
+ const mut = input;
59
+ if ('codec' in cell)
60
+ mut.codec = translateEnum('VideoCodec', cell.codec);
61
+ if ('targetSize' in cell)
62
+ mut.targetSize = cell.targetSize;
63
+ if ('crf' in cell)
64
+ mut.crf = cell.crf;
65
+ if ('preset' in cell)
66
+ mut.preset = translateEnum('VideoPreset', cell.preset);
67
+ if ('width' in cell)
68
+ mut.width = cell.width;
69
+ if ('height' in cell)
70
+ mut.height = cell.height;
71
+ if ('fit' in cell)
72
+ mut.fit = translateEnum('VideoFit', cell.fit);
73
+ if ('fps' in cell)
74
+ mut.fps = cell.fps;
75
+ if ('faststart' in cell)
76
+ mut.faststart = cell.faststart;
77
+ if ('audioCodec' in cell)
78
+ mut.audioCodec = translateEnum('AudioCodec', cell.audioCodec);
79
+ if ('audioBitrate' in cell)
80
+ mut.audioBitrate = translateEnum('AudioBitrate', cell.audioBitrate);
81
+ return new VideoCompressPresetOptions(input);
82
+ }
83
+ }
package/dist/errors.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { AuthErrorResponse, BalanceExhaustedResponse, FeatureNotAvailableResponse, FeatureTierRestrictedResponse, TierRestrictionResponse, WorkflowExpiredResponse } from '@giveitsmaller/contracts/openapi';
1
+ import type { AuthErrorResponse, BalanceExhaustedResponse, FeatureNotAvailableResponse, FeatureTierRestrictedResponse, ProbePendingResponse, TierRestrictionResponse, UploadDurationExceedsTierResponse, UploadSizeExceedsTierResponse, WorkflowExpiredResponse } from '@giveitsmaller/contracts/openapi';
2
2
  export declare class GislError extends Error {
3
3
  constructor(message: string);
4
4
  }
@@ -62,6 +62,37 @@ export declare class GislFeatureNotAvailableError extends GislApiError {
62
62
  readonly payload: FeatureNotAvailableResponse;
63
63
  constructor(statusCode: number, errorMessage: string, payload: FeatureNotAvailableResponse, path?: string, extra?: Omit<GislApiErrorOptions, 'payload'>);
64
64
  }
65
+ /**
66
+ * 422 response on `POST /api/workflows` when a job references an upload
67
+ * whose server-side probe hasn't completed at workflow-create time. The
68
+ * server rejects rather than silently routing as `short_form` (which
69
+ * hard-fails long video clips).
70
+ *
71
+ * **Recovery contract** (per contracts ProbePendingResponse docblock):
72
+ * poll `POST /api/uploads/{id}/probe` for the pending upload until
73
+ * `probe_status` is terminal (`ok` → re-`POST /api/workflows` the same
74
+ * request; `corrupt` / `unsupported_codec` → surface the probe error).
75
+ * The `Retry-After` response header (when present) suggests a delay
76
+ * in seconds before the next poll/retry.
77
+ *
78
+ * `payload.jobRef` identifies which job in the multi-job request triggered
79
+ * the probe-pending rejection.
80
+ *
81
+ * @example
82
+ * try {
83
+ * await client.createWorkflow({ jobs });
84
+ * } catch (e) {
85
+ * if (e instanceof GislProbePendingError) {
86
+ * await waitForProbe(e.payload.jobRef);
87
+ * // retry...
88
+ * }
89
+ * throw e;
90
+ * }
91
+ */
92
+ export declare class GislProbePendingError extends GislApiError {
93
+ readonly payload: ProbePendingResponse;
94
+ constructor(statusCode: number, errorMessage: string, payload: ProbePendingResponse, path?: string, extra?: Omit<GislApiErrorOptions, 'payload'>);
95
+ }
65
96
  export declare class GislWorkflowExpiredError extends GislApiError {
66
97
  readonly payload: WorkflowExpiredResponse;
67
98
  constructor(statusCode: number, errorMessage: string, payload: WorkflowExpiredResponse, path?: string, extra?: Omit<GislApiErrorOptions, 'payload'>);
@@ -70,9 +101,228 @@ export declare class GislAuthError extends GislApiError {
70
101
  readonly payload: AuthErrorResponse;
71
102
  constructor(statusCode: number, errorMessage: string, payload: AuthErrorResponse, path?: string, extra?: Omit<GislApiErrorOptions, 'payload'>);
72
103
  }
104
+ /**
105
+ * Discriminates the four upload-too-big shapes the server can return:
106
+ * - `size_tier` — 422 `upload_size_exceeds_tier` (typed payload present)
107
+ * - `duration_tier` — 422 `upload_duration_exceeds_tier` (typed payload present)
108
+ * - `absolute_413` — 413, the absolute across-tier cap. The contract models
109
+ * 413 as a plain `ErrorEnvelope` with NO `error_type`
110
+ * discriminator, so there is NO typed payload for it.
111
+ * - `cap_v2_multipart` — 422 `FILE_TOO_LARGE_FOR_MULTIPART` (SDK-3 / Wb6ebOMM,
112
+ * pre-S3 capacity reject on the resume-support endpoints).
113
+ * The contract carries no structured payload for this
114
+ * code today — `payload` is undefined for this kind.
115
+ *
116
+ * **Caveat for exhaustive-narrowing consumers.** The `cap_v2_multipart` value
117
+ * was added in TS SDK 0.5.0 / PHP SDK 0.3.0. A consumer writing
118
+ * `switch (e.kind) { case 'size_tier': ... case 'duration_tier': ... default:
119
+ * absurd(e.kind); }` against the prior 3-value union now sees a non-exhaustive
120
+ * switch and must add the new arm. The bump is logged in CHANGELOG.md.
121
+ */
122
+ export type GislUploadCapKind = 'size_tier' | 'duration_tier' | 'absolute_413' | 'cap_v2_multipart';
123
+ /**
124
+ * A single class covering all three "upload exceeds a size/duration cap"
125
+ * responses (422 size-tier, 422 duration-tier, 413 absolute).
126
+ *
127
+ * CONSCIOUS DEVIATION from the one-typed-payload-per-class invariant that the
128
+ * other structured subclasses follow (`GislBalanceExhaustedError`,
129
+ * `GislWorkflowExpiredError`, …). Justification: the card mandates this single
130
+ * `GislUploadCapExceededError` name and SDK-3 / E2E-1 are blocked-on it, so
131
+ * splitting into size/duration subclasses would break a cross-ticket naming
132
+ * contract; and 413 carries no typed envelope at all (plain `ErrorEnvelope`),
133
+ * so a one-payload-per-class split could not cover it uniformly anyway. The
134
+ * `kind` discriminant + a union-typed (possibly absent) `payload` is the
135
+ * deliberate trade-off. This is the only structured error in the tree that
136
+ * does not bind exactly one payload type — documented here in the same spirit
137
+ * as the inline PHP↔TS divergence notes.
138
+ *
139
+ * The two multipart-part errors below are deliberately NOT folded in with a
140
+ * `kind`: they carry different fields (`partNumber`/`uploadId` for an instance
141
+ * PUT failure vs `requiredParts`/`maxParts` for the count-ceiling guard) and
142
+ * are thrown from the multipart path, not the response handler.
143
+ */
144
+ export declare class GislUploadCapExceededError extends GislApiError {
145
+ readonly kind: GislUploadCapKind;
146
+ readonly payload: UploadSizeExceedsTierResponse | UploadDurationExceedsTierResponse | undefined;
147
+ constructor(statusCode: number, errorMessage: string, kind: GislUploadCapKind, payload: UploadSizeExceedsTierResponse | UploadDurationExceedsTierResponse | undefined, path?: string, extra?: Omit<GislApiErrorOptions, 'payload'>);
148
+ }
149
+ /**
150
+ * 404 `MULTIPART_SESSION_NOT_FOUND` — the durable multipart session referenced
151
+ * by a resume / status / presign / keepalive call cannot be located (expired
152
+ * past its 48h manifest TTL, deleted, or never existed). Thrown by the SDK-3
153
+ * resume-support endpoints (`getUploadStatus`, `presignParts`,
154
+ * `keepaliveUpload`, and the resume branch of `uploadFile`).
155
+ *
156
+ * Carries no typed structured payload — the contract for the 3 resume-support
157
+ * endpoints models this code as a plain `ErrorEnvelope`. Consumers should
158
+ * detect via `instanceof` and abandon the resume; a fresh `uploadFile()` call
159
+ * (without `resumeUploadId`) will start a new session.
160
+ */
161
+ export declare class GislMultipartSessionNotFoundError extends GislApiError {
162
+ constructor(statusCode: number, errorMessage: string, path?: string, options?: GislApiErrorOptions);
163
+ }
164
+ /**
165
+ * 403 `MULTIPART_SESSION_OWNERSHIP` — the caller is authenticated but the
166
+ * multipart session belongs to a different user. Thrown by the SDK-3
167
+ * resume-support endpoints. The session itself exists (otherwise the server
168
+ * would return 404 NOT_FOUND); the caller's identity simply doesn't match
169
+ * `manifest.userId`. Consumers should abandon the resume.
170
+ */
171
+ export declare class GislMultipartSessionOwnershipError extends GislApiError {
172
+ constructor(statusCode: number, errorMessage: string, path?: string, options?: GislApiErrorOptions);
173
+ }
174
+ /**
175
+ * 403 `MULTIPART_SESSION_AUTH_REQUIRED` — the multipart session was initiated
176
+ * anonymously (no `manifest.userId`) and the SDK-3 resume-support endpoints
177
+ * refuse to serve it on an authed caller. There is no "claim" workflow today
178
+ * to bind an authed identity to an anonymously-started session; that is the
179
+ * future flip tracked at upstream ticket 8LABloaz. Consumers hitting this on
180
+ * resume should abandon and re-upload from scratch under the authed identity.
181
+ */
182
+ export declare class GislMultipartSessionAuthRequiredError extends GislApiError {
183
+ constructor(statusCode: number, errorMessage: string, path?: string, options?: GislApiErrorOptions);
184
+ }
185
+ /**
186
+ * Optional structured metadata attached to a {@link GislConfigError}. The
187
+ * preset resolver (T4b) raises errors with these fields populated so
188
+ * callers can branch on machine-readable codes rather than parsing the
189
+ * human message. Every field is optional — existing call sites that
190
+ * throw `new GislConfigError(message)` keep working unchanged.
191
+ */
192
+ export interface GislConfigErrorMetadata {
193
+ /**
194
+ * Machine-readable error code. Resolver-side values today:
195
+ * `'invalid_combination'`, `'missing_dependency'`, `'type_mismatch'`,
196
+ * `'unknown_field'`, `'invalid_target_size'`. Other call sites may add
197
+ * codes — the union is open.
198
+ */
199
+ readonly reason?: string;
200
+ /**
201
+ * Field names (camelCase) that participated in the rejection. For
202
+ * `invalid_combination` reasons this is the *pair* that conflicts
203
+ * (e.g. `['targetSize', 'codec']`); for `missing_dependency` this is
204
+ * the dependent field plus the field whose value blocks it.
205
+ */
206
+ readonly conflictingFields?: readonly string[];
207
+ /**
208
+ * The merged wire-shape snapshot the resolver computed BEFORE the
209
+ * validation rejected it. Lets callers see "what would have been
210
+ * sent" for debugging without re-running the chain.
211
+ */
212
+ readonly resolvedSnapshot?: Readonly<Record<string, unknown>>;
213
+ /**
214
+ * Short human-readable remediation hint specific to the error. E.g.
215
+ * "Switch codec to H264, or drop targetSize and use crf instead."
216
+ */
217
+ readonly suggestion?: string;
218
+ }
219
+ /**
220
+ * Root of the LOCAL config-error tree — thrown before any HTTP/file I/O.
221
+ * Sibling of `GislApiError` (which represents server-side error envelopes).
222
+ * Reserve for fail-early errors raised by the ergonomic-layer factory or
223
+ * credential-chain resolver when the caller hasn't supplied something the
224
+ * SDK needs to make a request. Never carries an HTTP status code.
225
+ *
226
+ * Optional `metadata` (T4b — `27rE1fZn`) carries structured fields used
227
+ * by the preset resolver and other ergonomic-layer validators. Existing
228
+ * call sites that pass `(message)` keep working — metadata is purely
229
+ * additive and defaults to `undefined`.
230
+ */
231
+ export declare class GislConfigError extends GislError {
232
+ readonly reason?: string;
233
+ readonly conflictingFields?: readonly string[];
234
+ readonly resolvedSnapshot?: Readonly<Record<string, unknown>>;
235
+ readonly suggestion?: string;
236
+ constructor(message: string, metadata?: GislConfigErrorMetadata);
237
+ }
238
+ /**
239
+ * The ergonomic-layer factory `gisl.create()` could not resolve an API key
240
+ * from any of explicit arg, `GISL_API_KEY` env, or shared-config profile,
241
+ * AND the caller did not opt into anonymous or cookie-mode. Thrown BEFORE
242
+ * any file read or HTTP request — calls to `client.compress(...)`, `.run()`,
243
+ * etc., synchronously fail with this error.
244
+ */
245
+ export declare class GislMissingCredentialsError extends GislConfigError {
246
+ constructor(message: string);
247
+ }
248
+ /**
249
+ * The caller used `gisl.anonymous()` and then invoked an operation that is
250
+ * not in the anonymous-capable allowlist. Local-only — thrown before any I/O.
251
+ * Distinct from server-side `GislAuthError` (401/403 on the wire).
252
+ */
253
+ export declare class GislFeatureRequiresAuthError extends GislConfigError {
254
+ readonly operation: string;
255
+ constructor(operation: string, message: string);
256
+ }
257
+ /**
258
+ * `MergeBuilder.sequence(...)` referenced an asset that wasn't declared in
259
+ * the prior `client.merge(...)` call. Local validation runs BEFORE upload
260
+ * so the caller fails fast on the typo without burning bandwidth.
261
+ */
262
+ export declare class GislUndeclaredAssetError extends GislConfigError {
263
+ readonly assetId: string;
264
+ readonly declaredAssets: readonly string[];
265
+ constructor(assetId: string, declaredAssets: readonly string[]);
266
+ }
267
+ /**
268
+ * `MergeBuilder.sequence(...)` was called but at least one declared asset
269
+ * wasn't referenced. Almost always a bug (wasted upload). Escape via
270
+ * `allowUnusedAssets: true` on the merge options.
271
+ */
272
+ export declare class GislUnusedAssetError extends GislConfigError {
273
+ readonly unusedAssets: readonly string[];
274
+ constructor(unusedAssets: readonly string[]);
275
+ }
276
+ /**
277
+ * `MergeBuilder.sequence(...)` on an image merge was given a `clip(ref, opts)`
278
+ * entry. Image merges have NO per-input options in the wire today — `transition`
279
+ * applies at the merge level and is uniform across all joins.
280
+ */
281
+ export declare class GislPerInputOptionsNotSupportedError extends GislConfigError {
282
+ readonly mediaKind: string;
283
+ constructor(mediaKind: string);
284
+ }
285
+ /**
286
+ * Thrown by future chain methods (`.compress()` / `.thumbnail()` /
287
+ * `.convert()` on an `OperationBuilder`) when the previous step produces
288
+ * MULTIPLE artifacts and the caller didn't explicitly call `.mapEach(...)`
289
+ * to opt into per-artifact fan-out. T6 ships the error class + the
290
+ * `.mapEach(...)` method; the chain methods themselves are a separate
291
+ * follow-up card, so this error is currently dormant — but the type +
292
+ * audit-gate registration land here so the future chain-method PR is a
293
+ * pure addition with no public-API churn.
294
+ */
295
+ export declare class GislChainCardinalityMismatchError extends GislConfigError {
296
+ readonly previousOperation: string;
297
+ readonly attemptedOperation: string;
298
+ constructor(previousOperation: string, attemptedOperation: string);
299
+ }
73
300
  export declare class GislTimeoutError extends GislError {
74
301
  constructor(message: string);
75
302
  }
76
303
  export declare class GislAbortError extends GislError {
77
304
  constructor(message: string);
78
305
  }
306
+ /**
307
+ * A single S3 multipart part PUT failed terminally (after the configured
308
+ * retry attempts) or could not be read. Subclasses `GislError` — NOT
309
+ * `GislApiError` — because it carries no contract error envelope and is
310
+ * thrown from the multipart upload path, never from the response handler.
311
+ * Mirrors the `GislAbortError` shape, plus the failing part's identifiers.
312
+ */
313
+ export declare class GislMultipartPartError extends GislError {
314
+ readonly partNumber: number;
315
+ readonly uploadId: string;
316
+ constructor(message: string, partNumber: number, uploadId: string);
317
+ }
318
+ /**
319
+ * The upload would require more than the S3 hard limit of 10 000 multipart
320
+ * parts at the server-provided chunk size. Client-side guard (Model A: the
321
+ * server computes the part plan; the SDK asserts the ceiling). Subclasses
322
+ * `GislError` for the same reason as `GislMultipartPartError`.
323
+ */
324
+ export declare class GislMultipartPartCountError extends GislError {
325
+ readonly requiredParts: number;
326
+ readonly maxParts: number;
327
+ constructor(message: string, requiredParts: number, maxParts: number);
328
+ }