@giveitsmaller/sdk 0.19.0 → 0.21.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/LICENSE +202 -0
- package/README.md +8 -15
- package/dist/_audit.js +14 -4
- package/dist/builder.d.ts +5 -4
- package/dist/builder.js +16 -16
- package/dist/client.d.ts +17 -7
- package/dist/client.js +116 -62
- package/dist/ergonomic/image_output_routes.d.ts +30 -0
- package/dist/ergonomic/image_output_routes.js +82 -11
- package/dist/ergonomic/option_types.d.ts +34 -1
- package/dist/ergonomic/option_types.js +5 -1
- package/dist/ergonomic/option_validation.d.ts +19 -1
- package/dist/ergonomic/option_validation.js +34 -1
- package/dist/ergonomic/preset_resolver.d.ts +2 -2
- package/dist/ergonomic/preset_resolver.js +6 -10
- package/dist/ergonomic/presets/index.d.ts +9 -8
- package/dist/ergonomic/presets/index.js +1 -9
- package/dist/errors.d.ts +105 -3
- package/dist/errors.js +136 -2
- package/dist/file-first.d.ts +234 -16
- package/dist/file-first.js +692 -175
- package/dist/generated/sdk_spec/enums.d.ts +0 -26
- package/dist/generated/sdk_spec/enums.js +0 -16
- package/dist/generated/sdk_spec/errors.d.ts +1 -1
- package/dist/generated/sdk_spec/errors.js +12 -0
- package/dist/generated/sdk_spec/presets.js +0 -14
- package/dist/generated/sdk_spec/version.d.ts +2 -2
- package/dist/generated/sdk_spec/version.js +2 -2
- package/dist/gisl.d.ts +93 -5
- package/dist/gisl.js +72 -2
- package/dist/handle.d.ts +6 -1
- package/dist/handle.js +42 -13
- package/dist/index.core.d.ts +10 -8
- package/dist/index.core.js +11 -3
- package/dist/merge.d.ts +12 -0
- package/dist/merge.js +14 -2
- package/dist/retry-metadata.d.ts +37 -0
- package/dist/retry-metadata.js +86 -0
- package/dist/sse.d.ts +2 -1
- package/dist/sse.js +26 -6
- package/dist/types.d.ts +54 -4
- package/dist/types.js +1 -0
- package/package.json +3 -3
- package/dist/ergonomic/presets/document_pdf_compress.d.ts +0 -12
- package/dist/ergonomic/presets/document_pdf_compress.js +0 -33
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ResolvedOptions } from '../builder.js';
|
|
2
2
|
import type { OptimizeFor } from '../generated/sdk_spec/enums.js';
|
|
3
|
-
import { type PresetDefaults, type PresetMedia, type PresetOp } from './presets/index.js';
|
|
3
|
+
import { type PresetDefaults, type PresetMedia, type DetectedMedia, type PresetOp } from './presets/index.js';
|
|
4
4
|
/**
|
|
5
5
|
* The preset matrix version emitted on every resolve. Re-exported from the
|
|
6
6
|
* GENERATED `sdk_spec/version.ts` (source of truth: contracts
|
|
@@ -17,7 +17,7 @@ export declare const PRESET_VERSION: "1.6";
|
|
|
17
17
|
* extend the union.
|
|
18
18
|
*/
|
|
19
19
|
export interface ResolveCompressOptionsInput {
|
|
20
|
-
readonly media:
|
|
20
|
+
readonly media: DetectedMedia;
|
|
21
21
|
readonly op: PresetOp;
|
|
22
22
|
/** Defaults registered via `gisl.create({ presetDefaults: ... })`. */
|
|
23
23
|
readonly presetDefaults?: PresetDefaults;
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
import { sha256Hex } from '../sha256.js';
|
|
38
38
|
import { GislConfigError } from '../errors.js';
|
|
39
39
|
import { PRESET_VERSION as GENERATED_PRESET_VERSION } from '../generated/sdk_spec/version.js';
|
|
40
|
-
import { ImageCompressPresetOptions, AudioCompressPresetOptions, VideoCompressPresetOptions,
|
|
40
|
+
import { ImageCompressPresetOptions, AudioCompressPresetOptions, VideoCompressPresetOptions, DocumentOfficeCompressPresetOptions, DocumentOdfCompressPresetOptions, DocumentEpubCompressPresetOptions, definedFieldsOf, } from './presets/index.js';
|
|
41
41
|
/**
|
|
42
42
|
* The preset matrix version emitted on every resolve. Re-exported from the
|
|
43
43
|
* GENERATED `sdk_spec/version.ts` (source of truth: contracts
|
|
@@ -175,8 +175,6 @@ function sdkDefaultRecord(media, op, optimize) {
|
|
|
175
175
|
return { ...AudioCompressPresetOptions.shippedDefaultsFor(optimize) };
|
|
176
176
|
case 'video':
|
|
177
177
|
return { ...VideoCompressPresetOptions.shippedDefaultsFor(optimize) };
|
|
178
|
-
case 'document_pdf':
|
|
179
|
-
return { ...DocumentPdfCompressPresetOptions.shippedDefaultsFor(optimize) };
|
|
180
178
|
case 'document_office':
|
|
181
179
|
return { ...DocumentOfficeCompressPresetOptions.shippedDefaultsFor(optimize) };
|
|
182
180
|
case 'document_odf':
|
|
@@ -213,9 +211,6 @@ function presetDefaultsCellRecord(defaults, media, op, optimize) {
|
|
|
213
211
|
case 'video':
|
|
214
212
|
cell = defaults.cellFor('video', 'compress', optimize);
|
|
215
213
|
break;
|
|
216
|
-
case 'document_pdf':
|
|
217
|
-
cell = defaults.cellFor('document_pdf', 'compress', optimize);
|
|
218
|
-
break;
|
|
219
214
|
case 'document_office':
|
|
220
215
|
cell = defaults.cellFor('document_office', 'compress', optimize);
|
|
221
216
|
break;
|
|
@@ -252,7 +247,6 @@ const MEDIA_FIELDS = Object.freeze({
|
|
|
252
247
|
image: new Set(['quality', 'metadata', 'outputFormat']),
|
|
253
248
|
audio: new Set(['bitrate', 'channels', 'sampleRate', 'normalize']),
|
|
254
249
|
video: new Set(['codec', 'targetSize', 'crf', 'preset', 'width', 'height', 'fit', 'fps', 'faststart', 'audioCodec', 'audioBitrate']),
|
|
255
|
-
document_pdf: new Set(['profile', 'grayscale']),
|
|
256
250
|
document_office: new Set(['stripMacros', 'stripHiddenData', 'stripUnusedFonts']),
|
|
257
251
|
document_odf: new Set(['stripMetadata', 'stripUnusedStyles']),
|
|
258
252
|
document_epub: new Set(['fontSubsetting', 'stripUnusedCss']),
|
|
@@ -278,9 +272,9 @@ function detectMismatchedOverrides(media, overrides) {
|
|
|
278
272
|
const otherSet = MEDIA_FIELDS[otherMedia];
|
|
279
273
|
if (unknownFields.every((k) => otherSet.has(k))) {
|
|
280
274
|
// PascalCase every underscore-separated segment so multi-segment
|
|
281
|
-
// media (`
|
|
275
|
+
// media (`document_office` → `DocumentOffice…`) emit the actual exported
|
|
282
276
|
// class name (code-review MEDIUM: previously emitted
|
|
283
|
-
// `
|
|
277
|
+
// `Documentoffice…` which doesn't resolve in user code).
|
|
284
278
|
const className = otherMedia
|
|
285
279
|
.split('_')
|
|
286
280
|
.map((s) => s.charAt(0).toUpperCase() + s.slice(1))
|
|
@@ -321,7 +315,6 @@ export const KNOWN_WIRE_FIELDS = Object.freeze({
|
|
|
321
315
|
image: new Set(['quality', 'metadata', 'output_format']),
|
|
322
316
|
audio: new Set(['bitrate', 'channels', 'sample_rate', 'normalize', 'trim_start', 'trim_end']),
|
|
323
317
|
video: new Set(['codec', 'encoding_mode', 'crf', 'target_size_bytes', 'preset', 'width', 'height', 'fit', 'fps', 'faststart', 'audio_codec', 'audio_bitrate', 'trim_start', 'trim_end']),
|
|
324
|
-
document_pdf: new Set(['profile', 'grayscale']),
|
|
325
318
|
document_office: new Set(['strip_macros', 'strip_hidden_data', 'strip_unused_fonts']),
|
|
326
319
|
document_odf: new Set(['strip_metadata', 'strip_unused_styles']),
|
|
327
320
|
document_epub: new Set(['font_subsetting', 'strip_unused_css']),
|
|
@@ -444,6 +437,9 @@ function computePresetConfigHash(clientDefault, scopedDefault, callPresetOverrid
|
|
|
444
437
|
* `optimize` unset ⇒ layer 1 contributes nothing; `resolvedOptions.preset = null`.
|
|
445
438
|
*/
|
|
446
439
|
export function resolveCompressOptions(input) {
|
|
440
|
+
if (input.media === 'document_pdf') {
|
|
441
|
+
throw new GislConfigError('PDF compression was removed at contracts v2.166.0; convert() / transform() still accept PDF.', { reason: 'unsupported_media' });
|
|
442
|
+
}
|
|
447
443
|
const { media, op, presetDefaults, scopedPresetDefaults, presetOverrides, optimize, explicitOptions, audioLossless } = input;
|
|
448
444
|
if (op !== 'compress') {
|
|
449
445
|
throw new GislConfigError(`Preset resolution is only wired for compress operations today; got op='${op}'.`, { reason: 'unsupported_op' });
|
|
@@ -2,27 +2,31 @@ import { OptimizeFor } from '../../generated/sdk_spec/enums.js';
|
|
|
2
2
|
import { ImageCompressPresetOptions, type ImageCompressPresetOptionsInput } from './image_compress.js';
|
|
3
3
|
import { AudioCompressPresetOptions, type AudioCompressPresetOptionsInput } from './audio_compress.js';
|
|
4
4
|
import { VideoCompressPresetOptions, type VideoCompressPresetOptionsInput } from './video_compress.js';
|
|
5
|
-
import { DocumentPdfCompressPresetOptions, type DocumentPdfCompressPresetOptionsInput } from './document_pdf_compress.js';
|
|
6
5
|
import { DocumentOfficeCompressPresetOptions, type DocumentOfficeCompressPresetOptionsInput } from './document_office_compress.js';
|
|
7
6
|
import { DocumentOdfCompressPresetOptions, type DocumentOdfCompressPresetOptionsInput } from './document_odf_compress.js';
|
|
8
7
|
import { DocumentEpubCompressPresetOptions, type DocumentEpubCompressPresetOptionsInput } from './document_epub_compress.js';
|
|
9
8
|
export { ImageCompressPresetOptions, type ImageCompressPresetOptionsInput, } from './image_compress.js';
|
|
10
9
|
export { AudioCompressPresetOptions, type AudioCompressPresetOptionsInput, } from './audio_compress.js';
|
|
11
10
|
export { VideoCompressPresetOptions, type VideoCompressPresetOptionsInput, } from './video_compress.js';
|
|
12
|
-
export { DocumentPdfCompressPresetOptions, type DocumentPdfCompressPresetOptionsInput, } from './document_pdf_compress.js';
|
|
13
11
|
export { DocumentOfficeCompressPresetOptions, type DocumentOfficeCompressPresetOptionsInput, } from './document_office_compress.js';
|
|
14
12
|
export { DocumentOdfCompressPresetOptions, type DocumentOdfCompressPresetOptionsInput, } from './document_odf_compress.js';
|
|
15
13
|
export { DocumentEpubCompressPresetOptions, type DocumentEpubCompressPresetOptionsInput, } from './document_epub_compress.js';
|
|
16
|
-
export { OptimizeFor, ImageMetadataPolicy, ImageFormat, VideoCodec, VideoPreset, VideoFit, AudioBitrate, AudioCodec, AudioSampleRate,
|
|
14
|
+
export { OptimizeFor, ImageMetadataPolicy, ImageFormat, VideoCodec, VideoPreset, VideoFit, AudioBitrate, AudioCodec, AudioSampleRate, } from '../../generated/sdk_spec/enums.js';
|
|
17
15
|
/** Supported media×op pairs for preset cells in T4a. Compress-only. */
|
|
18
|
-
export type PresetMedia = 'image' | 'audio' | 'video' | '
|
|
16
|
+
export type PresetMedia = 'image' | 'audio' | 'video' | 'document_office' | 'document_odf' | 'document_epub';
|
|
17
|
+
/**
|
|
18
|
+
* Media the file-first detector can identify — the compressible
|
|
19
|
+
* `PresetMedia` set PLUS `document_pdf`, which is detectable (and a valid
|
|
20
|
+
* watermark-reject / convert / transform base) but NOT compressible.
|
|
21
|
+
*/
|
|
22
|
+
export type DetectedMedia = PresetMedia | 'document_pdf';
|
|
19
23
|
export type PresetOp = 'compress';
|
|
20
24
|
/**
|
|
21
25
|
* Union of leaf-DTO types the resolver will see from `cellFor()`.
|
|
22
26
|
* Discriminated by which `media` the caller passes — the type system
|
|
23
27
|
* narrows the return automatically via the overload set below.
|
|
24
28
|
*/
|
|
25
|
-
export type AnyPresetOptions = ImageCompressPresetOptions | AudioCompressPresetOptions | VideoCompressPresetOptions |
|
|
29
|
+
export type AnyPresetOptions = ImageCompressPresetOptions | AudioCompressPresetOptions | VideoCompressPresetOptions | DocumentOfficeCompressPresetOptions | DocumentOdfCompressPresetOptions | DocumentEpubCompressPresetOptions;
|
|
26
30
|
/**
|
|
27
31
|
* Per-cell field-merge: parent fields ⊕ child fields where defined.
|
|
28
32
|
* Re-construct the leaf DTO via the matching `<LeafClass>.from(merged)`
|
|
@@ -73,8 +77,6 @@ export declare class PresetDefaults {
|
|
|
73
77
|
audioCompress(level: OptimizeFor, input?: AudioCompressPresetOptionsInput): PresetDefaults;
|
|
74
78
|
/** Register a (level, delta) on the video-compress cell. Immutable. */
|
|
75
79
|
videoCompress(level: OptimizeFor, input?: VideoCompressPresetOptionsInput): PresetDefaults;
|
|
76
|
-
/** Register a (level, delta) on the document-pdf-compress cell. Immutable. */
|
|
77
|
-
pdfCompress(level: OptimizeFor, input?: DocumentPdfCompressPresetOptionsInput): PresetDefaults;
|
|
78
80
|
/** Register a (level, delta) on the document-office-compress cell. Immutable. */
|
|
79
81
|
officeCompress(level: OptimizeFor, input?: DocumentOfficeCompressPresetOptionsInput): PresetDefaults;
|
|
80
82
|
/** Register a (level, delta) on the document-odf-compress cell. Immutable. */
|
|
@@ -84,7 +86,6 @@ export declare class PresetDefaults {
|
|
|
84
86
|
/** @internal */ cellFor(media: 'image', op: 'compress', level: OptimizeFor): ImageCompressPresetOptions | undefined;
|
|
85
87
|
/** @internal */ cellFor(media: 'audio', op: 'compress', level: OptimizeFor): AudioCompressPresetOptions | undefined;
|
|
86
88
|
/** @internal */ cellFor(media: 'video', op: 'compress', level: OptimizeFor): VideoCompressPresetOptions | undefined;
|
|
87
|
-
/** @internal */ cellFor(media: 'document_pdf', op: 'compress', level: OptimizeFor): DocumentPdfCompressPresetOptions | undefined;
|
|
88
89
|
/** @internal */ cellFor(media: 'document_office', op: 'compress', level: OptimizeFor): DocumentOfficeCompressPresetOptions | undefined;
|
|
89
90
|
/** @internal */ cellFor(media: 'document_odf', op: 'compress', level: OptimizeFor): DocumentOdfCompressPresetOptions | undefined;
|
|
90
91
|
/** @internal */ cellFor(media: 'document_epub', op: 'compress', level: OptimizeFor): DocumentEpubCompressPresetOptions | undefined;
|
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
import { ImageCompressPresetOptions, } from './image_compress.js';
|
|
29
29
|
import { AudioCompressPresetOptions, } from './audio_compress.js';
|
|
30
30
|
import { VideoCompressPresetOptions, } from './video_compress.js';
|
|
31
|
-
import { DocumentPdfCompressPresetOptions, } from './document_pdf_compress.js';
|
|
32
31
|
import { DocumentOfficeCompressPresetOptions, } from './document_office_compress.js';
|
|
33
32
|
import { DocumentOdfCompressPresetOptions, } from './document_odf_compress.js';
|
|
34
33
|
import { DocumentEpubCompressPresetOptions, } from './document_epub_compress.js';
|
|
@@ -36,12 +35,11 @@ import { DocumentEpubCompressPresetOptions, } from './document_epub_compress.js'
|
|
|
36
35
|
export { ImageCompressPresetOptions, } from './image_compress.js';
|
|
37
36
|
export { AudioCompressPresetOptions, } from './audio_compress.js';
|
|
38
37
|
export { VideoCompressPresetOptions, } from './video_compress.js';
|
|
39
|
-
export { DocumentPdfCompressPresetOptions, } from './document_pdf_compress.js';
|
|
40
38
|
export { DocumentOfficeCompressPresetOptions, } from './document_office_compress.js';
|
|
41
39
|
export { DocumentOdfCompressPresetOptions, } from './document_odf_compress.js';
|
|
42
40
|
export { DocumentEpubCompressPresetOptions, } from './document_epub_compress.js';
|
|
43
41
|
// Re-export ergonomic enums for callers (single canonical path).
|
|
44
|
-
export { OptimizeFor, ImageMetadataPolicy, ImageFormat, VideoCodec, VideoPreset, VideoFit, AudioBitrate, AudioCodec, AudioSampleRate,
|
|
42
|
+
export { OptimizeFor, ImageMetadataPolicy, ImageFormat, VideoCodec, VideoPreset, VideoFit, AudioBitrate, AudioCodec, AudioSampleRate, } from '../../generated/sdk_spec/enums.js';
|
|
45
43
|
function cellKeyOf(media, op) {
|
|
46
44
|
return `${media}_${op}`;
|
|
47
45
|
}
|
|
@@ -89,8 +87,6 @@ function mergePresetOptions(cellKey, parentOpts, childOpts) {
|
|
|
89
87
|
return AudioCompressPresetOptions.from(mergedFields);
|
|
90
88
|
case 'video_compress':
|
|
91
89
|
return VideoCompressPresetOptions.from(mergedFields);
|
|
92
|
-
case 'document_pdf_compress':
|
|
93
|
-
return DocumentPdfCompressPresetOptions.from(mergedFields);
|
|
94
90
|
case 'document_office_compress':
|
|
95
91
|
return DocumentOfficeCompressPresetOptions.from(mergedFields);
|
|
96
92
|
case 'document_odf_compress':
|
|
@@ -178,10 +174,6 @@ export class PresetDefaults {
|
|
|
178
174
|
videoCompress(level, input = {}) {
|
|
179
175
|
return new PresetDefaults(withCellEntry(this.cells, 'video_compress', level, VideoCompressPresetOptions.from(input)));
|
|
180
176
|
}
|
|
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
177
|
/** Register a (level, delta) on the document-office-compress cell. Immutable. */
|
|
186
178
|
officeCompress(level, input = {}) {
|
|
187
179
|
return new PresetDefaults(withCellEntry(this.cells, 'document_office_compress', level, DocumentOfficeCompressPresetOptions.from(input)));
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type { AuthErrorResponse, AuthRejectionEnvelope, AuthRejectionEnvelopeErrorTypeEnum, BalanceExhaustedResponse, FeatureNotAvailableResponse, FeatureTierRestrictedResponse, ProbePendingResponse, TierRestrictionResponse, UploadDurationExceedsTierResponse, UploadSizeExceedsTierResponse, WorkflowExpiredResponse } from '@giveitsmaller/contracts/openapi';
|
|
1
|
+
import type { AuthErrorResponse, AuthRejectionEnvelope, AuthRejectionEnvelopeErrorTypeEnum, BalanceExhaustedResponse, FeatureNotAvailableResponse, FeatureTierRestrictedResponse, LongFormConcurrencyLimitResponse, ProbePendingResponse, TierRestrictionResponse, UploadDurationExceedsTierResponse, UploadSizeExceedsTierResponse, WorkflowExpiredResponse } from '@giveitsmaller/contracts/openapi';
|
|
2
|
+
import type { ErrorCategory } from './generated/sdk_spec/errors.js';
|
|
3
|
+
import type { RateLimitSnapshot } from './retry-metadata.js';
|
|
2
4
|
export declare class GislError extends Error {
|
|
3
5
|
constructor(message: string);
|
|
4
6
|
}
|
|
@@ -14,6 +16,11 @@ export interface GislApiErrorOptions {
|
|
|
14
16
|
readonly locale?: string;
|
|
15
17
|
readonly messageParams?: Record<string, unknown>;
|
|
16
18
|
readonly payload?: unknown;
|
|
19
|
+
/**
|
|
20
|
+
* The wire-stable machine error code (the response envelope's `error` field,
|
|
21
|
+
* SCREAMING_SNAKE, never localised). See {@link GislApiError.errorCode}.
|
|
22
|
+
*/
|
|
23
|
+
readonly errorCode?: string;
|
|
17
24
|
/**
|
|
18
25
|
* The response headers from the HTTP response that produced this error.
|
|
19
26
|
* Keys are LOWERCASED (HTTP header names are case-insensitive per RFC 9110,
|
|
@@ -33,6 +40,19 @@ export interface GislApiErrorOptions {
|
|
|
33
40
|
export declare class GislApiError extends GislError {
|
|
34
41
|
readonly statusCode: number;
|
|
35
42
|
readonly errorMessage: string;
|
|
43
|
+
/**
|
|
44
|
+
* The wire-stable machine error code — the response envelope's `error` field
|
|
45
|
+
* (SCREAMING_SNAKE, never localised). DISTINCT from {@link errorMessage},
|
|
46
|
+
* which is the human `message`. Mirrors the PHP `GislApiError.errorCode`.
|
|
47
|
+
*
|
|
48
|
+
* Optional here (PHP's is a required field defaulting to `'unknown_error'`):
|
|
49
|
+
* a DELIBERATE optional-vs-sentinel divergence — `undefined` when the wire
|
|
50
|
+
* envelope carries no `error` (e.g. a non-JSON / invalid-JSON response). When
|
|
51
|
+
* the wire DOES carry `error`, both SDKs surface the same value. Machine
|
|
52
|
+
* dispatch still keys off the typed subclasses (`payload.errorType`); this is
|
|
53
|
+
* the flat machine code for a base `GislApiError` (e.g. a plain 404).
|
|
54
|
+
*/
|
|
55
|
+
readonly errorCode?: string;
|
|
36
56
|
readonly path?: string;
|
|
37
57
|
readonly details?: unknown;
|
|
38
58
|
readonly messageKey?: string;
|
|
@@ -53,6 +73,42 @@ export declare class GislApiError extends GislError {
|
|
|
53
73
|
*/
|
|
54
74
|
readonly contentLanguage?: string;
|
|
55
75
|
constructor(statusCode: number, errorMessage: string, path?: string, details?: unknown, options?: GislApiErrorOptions);
|
|
76
|
+
/**
|
|
77
|
+
* Resolve the generated `ERROR_CODES` entry for this error, SOURCE-AWARE
|
|
78
|
+
* (plan D1). ~9 registry codes are keyed by the `error_type` discriminator
|
|
79
|
+
* rather than the envelope `error` field, so try the typed discriminator
|
|
80
|
+
* FIRST (camel `errorType`, raw-snake `error_type` fallback), then fall back
|
|
81
|
+
* to the flat machine {@link errorCode}. Returns `undefined` when neither
|
|
82
|
+
* resolves — e.g. a bare base error whose payload carries no discriminator.
|
|
83
|
+
* NEVER throws on a missing payload / discriminator.
|
|
84
|
+
*/
|
|
85
|
+
private resolveErrorEntry;
|
|
86
|
+
/**
|
|
87
|
+
* Whether retrying this request could plausibly succeed. `true` when the HTTP
|
|
88
|
+
* status is inherently retryable (408 / 429 / 5xx) OR the resolved taxonomy
|
|
89
|
+
* entry marks the code retryable (e.g. `probe_pending`). Note: logical OR
|
|
90
|
+
* (not `??`) — a 429 is retryable regardless of the taxonomy, and a
|
|
91
|
+
* registry-retryable code is retryable regardless of status.
|
|
92
|
+
*/
|
|
93
|
+
get retryable(): boolean;
|
|
94
|
+
/**
|
|
95
|
+
* The taxonomy category for this error's machine code, from the generated
|
|
96
|
+
* `ERROR_CODES` registry, or `undefined` when the code isn't in the registry
|
|
97
|
+
* (e.g. a bare base error whose payload carries no discriminator).
|
|
98
|
+
*/
|
|
99
|
+
get category(): ErrorCategory | undefined;
|
|
100
|
+
/**
|
|
101
|
+
* The rate-limit snapshot parsed from the `x-ratelimit-*` response headers,
|
|
102
|
+
* or `undefined` when they aren't all present as non-negative integers. Read
|
|
103
|
+
* this after a 429 to schedule a back-off.
|
|
104
|
+
*/
|
|
105
|
+
get rateLimit(): RateLimitSnapshot | undefined;
|
|
106
|
+
/**
|
|
107
|
+
* The server-suggested back-off delay in whole seconds, parsed from the
|
|
108
|
+
* `Retry-After` response header, or `undefined` when absent / zero / past /
|
|
109
|
+
* malformed. Mirrors the retry-loop parser's semantics.
|
|
110
|
+
*/
|
|
111
|
+
get retryAfterSeconds(): number | undefined;
|
|
56
112
|
}
|
|
57
113
|
/**
|
|
58
114
|
* Shape of a single validation detail entry. Mirrors the v2
|
|
@@ -78,6 +134,34 @@ export declare class GislBalanceExhaustedError extends GislApiError {
|
|
|
78
134
|
readonly payload: BalanceExhaustedResponse;
|
|
79
135
|
constructor(statusCode: number, errorMessage: string, payload: BalanceExhaustedResponse, path?: string, extra?: Omit<GislApiErrorOptions, 'payload'>);
|
|
80
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* `429` on `POST /api/workflows` when the caller already holds the maximum
|
|
139
|
+
* number of concurrent in-flight long-form (Fargate) workflows their tier
|
|
140
|
+
* permits (Pro 2 / Max 5; Enterprise uncapped). DISTINCT from an infrastructure
|
|
141
|
+
* rate-limit `429`: it carries the machine code `LONG_FORM_CONCURRENCY_LIMIT_EXCEEDED`
|
|
142
|
+
* and a `links.upgrade` deep link, and has **no `Retry-After`** — the limit clears
|
|
143
|
+
* when an in-flight long-form workflow finishes, not on a timer. A generic infra
|
|
144
|
+
* rate-limit `429` (no matching code) surfaces as the base {@link GislApiError}
|
|
145
|
+
* instead, where {@link GislApiError.retryAfterSeconds} applies.
|
|
146
|
+
*
|
|
147
|
+
* Dispatched on the `error` CODE, not `error_type` (the envelope carries none).
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* try {
|
|
151
|
+
* await client.createWorkflow({ jobs });
|
|
152
|
+
* } catch (e) {
|
|
153
|
+
* if (e instanceof GislLongFormConcurrencyError) {
|
|
154
|
+
* showUpgradeCta(e.upgradeUrl); // wait on completion or upgrade — do NOT back off
|
|
155
|
+
* }
|
|
156
|
+
* throw e;
|
|
157
|
+
* }
|
|
158
|
+
*/
|
|
159
|
+
export declare class GislLongFormConcurrencyError extends GislApiError {
|
|
160
|
+
readonly payload: LongFormConcurrencyLimitResponse;
|
|
161
|
+
constructor(statusCode: number, errorMessage: string, payload: LongFormConcurrencyLimitResponse, path?: string, extra?: Omit<GislApiErrorOptions, 'payload'>);
|
|
162
|
+
/** The pricing / upgrade deep link (`links.upgrade`), or `undefined` when absent. */
|
|
163
|
+
get upgradeUrl(): string | undefined;
|
|
164
|
+
}
|
|
81
165
|
export declare class GislTierRestrictedError extends GislApiError {
|
|
82
166
|
readonly payload: TierRestrictionResponse;
|
|
83
167
|
constructor(statusCode: number, errorMessage: string, payload: TierRestrictionResponse, path?: string, extra?: Omit<GislApiErrorOptions, 'payload'>);
|
|
@@ -355,7 +439,25 @@ export declare class GislBundleAlreadyArchivedError extends GislConfigError {
|
|
|
355
439
|
constructor();
|
|
356
440
|
}
|
|
357
441
|
export declare class GislTimeoutError extends GislError {
|
|
358
|
-
|
|
442
|
+
/**
|
|
443
|
+
* The workflow this timeout is scoped to, when the SDK knows it. Set on a
|
|
444
|
+
* timed-out `run()` / `wait()` / poll / download once the workflow has been
|
|
445
|
+
* created: a timeout does NOT mean the work failed — the server keeps
|
|
446
|
+
* processing, so poll `client.getWorkflowStatus(workflowId)` /
|
|
447
|
+
* `getWorkflowDownloads(workflowId)` to recover a result that completed after
|
|
448
|
+
* the deadline, instead of re-running (a re-run re-uploads and, for
|
|
449
|
+
* authenticated callers, settles a SECOND charge for the same deliverable).
|
|
450
|
+
*
|
|
451
|
+
* `undefined` when the SDK has no id to offer. That is NOT a guarantee that
|
|
452
|
+
* nothing was created or charged: it covers both the safe case (an upload /
|
|
453
|
+
* probe timeout before any workflow existed) AND the AMBIGUOUS case (the
|
|
454
|
+
* `POST /api/workflows` request itself timed out — the server may have
|
|
455
|
+
* created and charged the workflow before its response was lost). Treat an
|
|
456
|
+
* absent id as "cannot auto-recover", not "clean slate": reconcile (e.g. list
|
|
457
|
+
* recent workflows) before re-running rather than assuming nothing happened.
|
|
458
|
+
*/
|
|
459
|
+
readonly workflowId?: string;
|
|
460
|
+
constructor(message: string, workflowId?: string);
|
|
359
461
|
}
|
|
360
462
|
/**
|
|
361
463
|
* Transport-level failure: the underlying `fetch` (or other transport) could
|
|
@@ -439,7 +541,7 @@ export type GislSinkErrorReason = 'not_single_output' | 'downloader_unavailable'
|
|
|
439
541
|
/**
|
|
440
542
|
* Thrown by the file-first `RunResult` sinks (`toFile()` / `downloadTo()`,
|
|
441
543
|
* FF1) when they cannot deliver. The machine-readable `reason` discriminates
|
|
442
|
-
* the
|
|
544
|
+
* the six cases below, mirroring the `reason`-bag convention on
|
|
443
545
|
* {@link GislConfigError}:
|
|
444
546
|
*
|
|
445
547
|
* - `not_single_output` — `toFile()` requires exactly one output but the
|
package/dist/errors.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
// W8v4jWzx — the generated error-taxonomy registry stays INTERNAL to this
|
|
2
|
+
// module (only the `ErrorCategory` TYPE is re-exported from the public barrel).
|
|
3
|
+
import { ERROR_CODES } from './generated/sdk_spec/errors.js';
|
|
4
|
+
import { isApiRetryableStatus, rateLimitFromHeaders, retryAfterSecondsFromHeaders, } from './retry-metadata.js';
|
|
5
|
+
// Registry keys are lowercase_snake; normalise the wire code / discriminator
|
|
6
|
+
// (trim + lowercase) before looking it up in ERROR_CODES.
|
|
7
|
+
function normalizeErrorCode(rawCode) {
|
|
8
|
+
return rawCode.trim().toLowerCase();
|
|
9
|
+
}
|
|
1
10
|
export class GislError extends Error {
|
|
2
11
|
constructor(message) {
|
|
3
12
|
super(message);
|
|
@@ -7,6 +16,19 @@ export class GislError extends Error {
|
|
|
7
16
|
export class GislApiError extends GislError {
|
|
8
17
|
statusCode;
|
|
9
18
|
errorMessage;
|
|
19
|
+
/**
|
|
20
|
+
* The wire-stable machine error code — the response envelope's `error` field
|
|
21
|
+
* (SCREAMING_SNAKE, never localised). DISTINCT from {@link errorMessage},
|
|
22
|
+
* which is the human `message`. Mirrors the PHP `GislApiError.errorCode`.
|
|
23
|
+
*
|
|
24
|
+
* Optional here (PHP's is a required field defaulting to `'unknown_error'`):
|
|
25
|
+
* a DELIBERATE optional-vs-sentinel divergence — `undefined` when the wire
|
|
26
|
+
* envelope carries no `error` (e.g. a non-JSON / invalid-JSON response). When
|
|
27
|
+
* the wire DOES carry `error`, both SDKs surface the same value. Machine
|
|
28
|
+
* dispatch still keys off the typed subclasses (`payload.errorType`); this is
|
|
29
|
+
* the flat machine code for a base `GislApiError` (e.g. a plain 404).
|
|
30
|
+
*/
|
|
31
|
+
errorCode;
|
|
10
32
|
path;
|
|
11
33
|
details;
|
|
12
34
|
messageKey;
|
|
@@ -41,10 +63,69 @@ export class GislApiError extends GislError {
|
|
|
41
63
|
this.locale = options.locale;
|
|
42
64
|
this.messageParams = options.messageParams;
|
|
43
65
|
this.payload = options.payload;
|
|
66
|
+
this.errorCode = options.errorCode;
|
|
44
67
|
this.responseHeaders = options.responseHeaders;
|
|
45
68
|
this.contentLanguage = options.contentLanguage;
|
|
46
69
|
}
|
|
47
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Resolve the generated `ERROR_CODES` entry for this error, SOURCE-AWARE
|
|
73
|
+
* (plan D1). ~9 registry codes are keyed by the `error_type` discriminator
|
|
74
|
+
* rather than the envelope `error` field, so try the typed discriminator
|
|
75
|
+
* FIRST (camel `errorType`, raw-snake `error_type` fallback), then fall back
|
|
76
|
+
* to the flat machine {@link errorCode}. Returns `undefined` when neither
|
|
77
|
+
* resolves — e.g. a bare base error whose payload carries no discriminator.
|
|
78
|
+
* NEVER throws on a missing payload / discriminator.
|
|
79
|
+
*/
|
|
80
|
+
resolveErrorEntry() {
|
|
81
|
+
const payload = this.payload;
|
|
82
|
+
const rawErrorType = payload?.errorType ?? payload?.error_type;
|
|
83
|
+
if (typeof rawErrorType === 'string') {
|
|
84
|
+
const byType = ERROR_CODES[normalizeErrorCode(rawErrorType)];
|
|
85
|
+
if (byType !== undefined)
|
|
86
|
+
return byType;
|
|
87
|
+
}
|
|
88
|
+
if (this.errorCode !== undefined) {
|
|
89
|
+
const byCode = ERROR_CODES[normalizeErrorCode(this.errorCode)];
|
|
90
|
+
if (byCode !== undefined)
|
|
91
|
+
return byCode;
|
|
92
|
+
}
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Whether retrying this request could plausibly succeed. `true` when the HTTP
|
|
97
|
+
* status is inherently retryable (408 / 429 / 5xx) OR the resolved taxonomy
|
|
98
|
+
* entry marks the code retryable (e.g. `probe_pending`). Note: logical OR
|
|
99
|
+
* (not `??`) — a 429 is retryable regardless of the taxonomy, and a
|
|
100
|
+
* registry-retryable code is retryable regardless of status.
|
|
101
|
+
*/
|
|
102
|
+
get retryable() {
|
|
103
|
+
return (isApiRetryableStatus(this.statusCode) || (this.resolveErrorEntry()?.retryable ?? false));
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The taxonomy category for this error's machine code, from the generated
|
|
107
|
+
* `ERROR_CODES` registry, or `undefined` when the code isn't in the registry
|
|
108
|
+
* (e.g. a bare base error whose payload carries no discriminator).
|
|
109
|
+
*/
|
|
110
|
+
get category() {
|
|
111
|
+
return this.resolveErrorEntry()?.category;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The rate-limit snapshot parsed from the `x-ratelimit-*` response headers,
|
|
115
|
+
* or `undefined` when they aren't all present as non-negative integers. Read
|
|
116
|
+
* this after a 429 to schedule a back-off.
|
|
117
|
+
*/
|
|
118
|
+
get rateLimit() {
|
|
119
|
+
return rateLimitFromHeaders(this.responseHeaders);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* The server-suggested back-off delay in whole seconds, parsed from the
|
|
123
|
+
* `Retry-After` response header, or `undefined` when absent / zero / past /
|
|
124
|
+
* malformed. Mirrors the retry-loop parser's semantics.
|
|
125
|
+
*/
|
|
126
|
+
get retryAfterSeconds() {
|
|
127
|
+
return retryAfterSecondsFromHeaders(this.responseHeaders);
|
|
128
|
+
}
|
|
48
129
|
}
|
|
49
130
|
export class GislValidationError extends GislApiError {
|
|
50
131
|
constructor(statusCode, errorMessage, details, path, options) {
|
|
@@ -64,6 +145,38 @@ export class GislBalanceExhaustedError extends GislApiError {
|
|
|
64
145
|
this.name = 'GislBalanceExhaustedError';
|
|
65
146
|
}
|
|
66
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* `429` on `POST /api/workflows` when the caller already holds the maximum
|
|
150
|
+
* number of concurrent in-flight long-form (Fargate) workflows their tier
|
|
151
|
+
* permits (Pro 2 / Max 5; Enterprise uncapped). DISTINCT from an infrastructure
|
|
152
|
+
* rate-limit `429`: it carries the machine code `LONG_FORM_CONCURRENCY_LIMIT_EXCEEDED`
|
|
153
|
+
* and a `links.upgrade` deep link, and has **no `Retry-After`** — the limit clears
|
|
154
|
+
* when an in-flight long-form workflow finishes, not on a timer. A generic infra
|
|
155
|
+
* rate-limit `429` (no matching code) surfaces as the base {@link GislApiError}
|
|
156
|
+
* instead, where {@link GislApiError.retryAfterSeconds} applies.
|
|
157
|
+
*
|
|
158
|
+
* Dispatched on the `error` CODE, not `error_type` (the envelope carries none).
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* try {
|
|
162
|
+
* await client.createWorkflow({ jobs });
|
|
163
|
+
* } catch (e) {
|
|
164
|
+
* if (e instanceof GislLongFormConcurrencyError) {
|
|
165
|
+
* showUpgradeCta(e.upgradeUrl); // wait on completion or upgrade — do NOT back off
|
|
166
|
+
* }
|
|
167
|
+
* throw e;
|
|
168
|
+
* }
|
|
169
|
+
*/
|
|
170
|
+
export class GislLongFormConcurrencyError extends GislApiError {
|
|
171
|
+
constructor(statusCode, errorMessage, payload, path, extra) {
|
|
172
|
+
super(statusCode, errorMessage, path, undefined, buildOptionsWithPayload(payload, extra));
|
|
173
|
+
this.name = 'GislLongFormConcurrencyError';
|
|
174
|
+
}
|
|
175
|
+
/** The pricing / upgrade deep link (`links.upgrade`), or `undefined` when absent. */
|
|
176
|
+
get upgradeUrl() {
|
|
177
|
+
return this.payload.links?.upgrade;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
67
180
|
export class GislTierRestrictedError extends GislApiError {
|
|
68
181
|
constructor(statusCode, errorMessage, payload, path, extra) {
|
|
69
182
|
super(statusCode, errorMessage, path, undefined, buildOptionsWithPayload(payload, extra));
|
|
@@ -366,9 +479,30 @@ export class GislBundleAlreadyArchivedError extends GislConfigError {
|
|
|
366
479
|
}
|
|
367
480
|
}
|
|
368
481
|
export class GislTimeoutError extends GislError {
|
|
369
|
-
|
|
482
|
+
/**
|
|
483
|
+
* The workflow this timeout is scoped to, when the SDK knows it. Set on a
|
|
484
|
+
* timed-out `run()` / `wait()` / poll / download once the workflow has been
|
|
485
|
+
* created: a timeout does NOT mean the work failed — the server keeps
|
|
486
|
+
* processing, so poll `client.getWorkflowStatus(workflowId)` /
|
|
487
|
+
* `getWorkflowDownloads(workflowId)` to recover a result that completed after
|
|
488
|
+
* the deadline, instead of re-running (a re-run re-uploads and, for
|
|
489
|
+
* authenticated callers, settles a SECOND charge for the same deliverable).
|
|
490
|
+
*
|
|
491
|
+
* `undefined` when the SDK has no id to offer. That is NOT a guarantee that
|
|
492
|
+
* nothing was created or charged: it covers both the safe case (an upload /
|
|
493
|
+
* probe timeout before any workflow existed) AND the AMBIGUOUS case (the
|
|
494
|
+
* `POST /api/workflows` request itself timed out — the server may have
|
|
495
|
+
* created and charged the workflow before its response was lost). Treat an
|
|
496
|
+
* absent id as "cannot auto-recover", not "clean slate": reconcile (e.g. list
|
|
497
|
+
* recent workflows) before re-running rather than assuming nothing happened.
|
|
498
|
+
*/
|
|
499
|
+
workflowId;
|
|
500
|
+
constructor(message, workflowId) {
|
|
370
501
|
super(message);
|
|
371
502
|
this.name = 'GislTimeoutError';
|
|
503
|
+
// Normalise an empty id to "absent" — an empty string is not a usable
|
|
504
|
+
// recovery handle (some throw sites derive the id as `… ?? ''`).
|
|
505
|
+
this.workflowId = workflowId === '' ? undefined : workflowId;
|
|
372
506
|
}
|
|
373
507
|
}
|
|
374
508
|
/**
|
|
@@ -479,7 +613,7 @@ export class GislResultNotReadyError extends GislError {
|
|
|
479
613
|
/**
|
|
480
614
|
* Thrown by the file-first `RunResult` sinks (`toFile()` / `downloadTo()`,
|
|
481
615
|
* FF1) when they cannot deliver. The machine-readable `reason` discriminates
|
|
482
|
-
* the
|
|
616
|
+
* the six cases below, mirroring the `reason`-bag convention on
|
|
483
617
|
* {@link GislConfigError}:
|
|
484
618
|
*
|
|
485
619
|
* - `not_single_output` — `toFile()` requires exactly one output but the
|