@giveitsmaller/sdk 0.12.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -25
- package/dist/client.d.ts +45 -8
- package/dist/client.js +151 -7
- package/dist/ergonomic/preset_resolver.d.ts +1 -0
- package/dist/ergonomic/preset_resolver.js +4 -1
- package/dist/file-first.d.ts +1 -1
- package/dist/file-first.js +1 -1
- package/dist/index.core.d.ts +1 -1
- package/dist/types.d.ts +37 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -12,34 +12,42 @@ Node.js 18+ required.
|
|
|
12
12
|
|
|
13
13
|
## Quickstart
|
|
14
14
|
|
|
15
|
+
The SDK is **file-first**: you start from a file (`.file(path)` for one,
|
|
16
|
+
`.files([paths])` for many) and call operations *on* it — upload, workflow
|
|
17
|
+
creation, and waiting all happen for you.
|
|
18
|
+
|
|
15
19
|
```ts
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
await client.waitForWorkflow(workflow.workflowId);
|
|
38
|
-
|
|
39
|
-
const dls = await client.getWorkflowDownloads(workflow.workflowId);
|
|
40
|
-
console.log('Compressed:', dls.downloads[0].files[0].downloadUrl);
|
|
20
|
+
import { gisl, OptimizeFor } from '@giveitsmaller/sdk';
|
|
21
|
+
|
|
22
|
+
// baseUrl defaults to https://api.giveitsmaller.com; the key can also come
|
|
23
|
+
// from GISL_API_KEY or ~/.gisl/credentials.
|
|
24
|
+
const client = await gisl.create({ apiKey: 'sk_...' });
|
|
25
|
+
|
|
26
|
+
// One file:
|
|
27
|
+
const result = await client
|
|
28
|
+
.file('./photo.jpg')
|
|
29
|
+
.compress(OptimizeFor.Balanced)
|
|
30
|
+
.run({ maxWait: '5m' });
|
|
31
|
+
|
|
32
|
+
console.log(result.url); // pre-signed download URL
|
|
33
|
+
|
|
34
|
+
// Many files (fan-out) — the same chain:
|
|
35
|
+
const many = await client
|
|
36
|
+
.files(['./a.jpg', './b.png'])
|
|
37
|
+
.compress(OptimizeFor.Balanced)
|
|
38
|
+
.run();
|
|
39
|
+
|
|
40
|
+
for (const artifact of many.artifacts) console.log(artifact.url);
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
+
> **Operation-first / low-level also ships.** A lower-level
|
|
44
|
+
> `client.compress(path, { ... }).run()` form (and `thumbnail` / `convert`) is
|
|
45
|
+
> available, and the raw wire client — `client.createWorkflow({ jobs: [...] })`
|
|
46
|
+
> with `uploadSource` / `OperationType` for hand-built job DAGs — is the advanced
|
|
47
|
+
> escape hatch. File-first is the recommended direction the
|
|
48
|
+
> [examples](https://github.com/AntonioCS/giveitsmaller-sdks/tree/main/docs/typescript/examples)
|
|
49
|
+
> build on.
|
|
50
|
+
|
|
43
51
|
> **Reusing an upload id across clients?** An upload created by an
|
|
44
52
|
> authenticated caller is owned by that caller. If you persist a `fileId` and
|
|
45
53
|
> later reference it (via `fileInput.uploadId(id)`) from a client configured
|
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AudioWatermarkDecodeRequest, AudioWatermarkDecodeResponse, ExternalImportCreatedResponse, ExternalImportRequest, LoginUserRequest, LoginUser200ResponseData, ContactRequest, CreditsBalanceResponse, CreditsUsageResponse, UploadResponse, UploadProbeResponse, WorkflowCancelResponse, WorkflowCreateResponse, WorkflowResumeResponse, WorkflowStatusResponse, WorkflowListResponse, WorkflowSummary, WorkflowDownloadResponse, MetadataResponse, RetryResponse } from '@giveitsmaller/contracts/openapi';
|
|
2
|
-
import type { CreditsUsageOptions, ListWorkflowsOptions, GetSchemaOptions, GetSchemaResult, GislClientConfig, GislSseEvent, PreflightClipsResult, UploadOptions, WaitOptions, WorkflowCreatePayload, _Sdk3HandCodedKeepaliveResult, _Sdk3HandCodedMultipartStatusResult, _Sdk3HandCodedPresignPartsResult } from './types.js';
|
|
2
|
+
import type { CreditsUsageOptions, ListWorkflowsOptions, GetSchemaOptions, GetSchemaResult, GislClientConfig, GislSseEvent, PreflightClipsResult, ProbeWaitOptions, ProbeWaitResult, UploadOptions, WaitOptions, WorkflowCreatePayload, _Sdk3HandCodedKeepaliveResult, _Sdk3HandCodedMultipartStatusResult, _Sdk3HandCodedPresignPartsResult } from './types.js';
|
|
3
3
|
export declare const MULTIPART_CONCURRENCY_DEFAULT: 4;
|
|
4
4
|
export declare const DEFAULT_MULTIPART_FIRST_CHUNK_SIZE: number;
|
|
5
5
|
export interface ValidationDetail {
|
|
@@ -306,15 +306,52 @@ export declare class GislClient {
|
|
|
306
306
|
/**
|
|
307
307
|
* Probe an uploaded file for workflow-readiness — detects corruption,
|
|
308
308
|
* unsupported codecs, and pre-assigns the processing class the server
|
|
309
|
-
* would route the file to.
|
|
310
|
-
*
|
|
309
|
+
* would route the file to. For video uploads the probe also lands the
|
|
310
|
+
* codec + duration the server needs to admit the parallel split, so
|
|
311
|
+
* calling this (or {@link waitForProbe}) before workflow-create is the
|
|
312
|
+
* structural unlock for the fast video path on the multipart flow.
|
|
311
313
|
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
*
|
|
315
|
-
*
|
|
314
|
+
* Endpoint availability is `stable`. The probe runs asynchronously after
|
|
315
|
+
* upload: until the result has landed, this returns `422`
|
|
316
|
+
* `feature_not_available` (surfaced as {@link GislFeatureNotAvailableError})
|
|
317
|
+
* — i.e. that 422 means "probe not landed yet", NOT "not implemented". Once
|
|
318
|
+
* landed it returns a `200` with any `probeStatus`. Idempotent: probing the
|
|
319
|
+
* same `fileId` twice returns the cached result. See {@link waitForProbe}
|
|
320
|
+
* for a bounded poll that turns this into a single ready/gave-up answer.
|
|
321
|
+
*/
|
|
322
|
+
probeUpload(fileId: string, options?: {
|
|
323
|
+
signal?: AbortSignal;
|
|
324
|
+
}): Promise<UploadProbeResponse>;
|
|
325
|
+
/**
|
|
326
|
+
* Bounded poll of {@link probeUpload} until the probe lands — the helper
|
|
327
|
+
* frontends call between upload-complete and workflow-create so the server
|
|
328
|
+
* sees the video's codec + duration and admits the ~3× parallel split.
|
|
329
|
+
*
|
|
330
|
+
* Loop (per the API wire contract):
|
|
331
|
+
* - `422 feature_not_available` → probe not landed yet → keep polling
|
|
332
|
+
* (exponential full-jitter backoff, honouring a `Retry-After` header when
|
|
333
|
+
* present, clamped to the remaining budget).
|
|
334
|
+
* - any `200` → STOP. Resolves `{ landed: true, probe }` regardless of
|
|
335
|
+
* `probeStatus` (ok / corrupt / unsupported_codec / missing_metadata) —
|
|
336
|
+
* the server + fan-out gate decide split-vs-single from the landed
|
|
337
|
+
* metadata; the SDK does not interpret it.
|
|
338
|
+
* - `5xx` (prober crash) → retry a couple of times, then give up.
|
|
339
|
+
* - timeout → give up.
|
|
340
|
+
*
|
|
341
|
+
* **Never bounces:** on give-up (timeout / repeated 5xx / transport) it
|
|
342
|
+
* resolves `{ landed: false, reason }` rather than throwing, so the caller
|
|
343
|
+
* proceeds to create the workflow anyway (the server's size heuristic routes
|
|
344
|
+
* it; worst case = today's single-task behaviour). Genuine failures —
|
|
345
|
+
* `404 upload_not_found`, auth errors, or caller abort — DO propagate (they
|
|
346
|
+
* are not "probe not ready"), so a real problem is never silently swallowed.
|
|
347
|
+
*
|
|
348
|
+
* `timeoutMs` bounds the OVERALL poll, checked between attempts; each
|
|
349
|
+
* in-flight probe request is bounded by the client's own per-request timeout
|
|
350
|
+
* (a hung request surfaces as a transient and the next deadline check gives
|
|
351
|
+
* up). So a single slow probe may run up to one client-request-timeout before
|
|
352
|
+
* the wait returns.
|
|
316
353
|
*/
|
|
317
|
-
|
|
354
|
+
waitForProbe(fileId: string, options?: ProbeWaitOptions): Promise<ProbeWaitResult>;
|
|
318
355
|
/**
|
|
319
356
|
* Probe N uploaded files in parallel and partition the results by
|
|
320
357
|
* outcome. Returns `{ ok, rejected, errors }` so the caller can
|
package/dist/client.js
CHANGED
|
@@ -112,6 +112,51 @@ function isRetryableStatus(status) {
|
|
|
112
112
|
function isRetryableNetworkError(err) {
|
|
113
113
|
return err instanceof TypeError;
|
|
114
114
|
}
|
|
115
|
+
// Parse an HTTP `Retry-After` header into milliseconds. Accepts the two RFC
|
|
116
|
+
// 9110 forms: delta-seconds (e.g. "5") or an HTTP-date. Returns `undefined`
|
|
117
|
+
// for an absent / unparseable / negative value (caller falls back to its own
|
|
118
|
+
// backoff). A past HTTP-date clamps to 0.
|
|
119
|
+
function parseRetryAfterMs(headerValue) {
|
|
120
|
+
if (headerValue === undefined)
|
|
121
|
+
return undefined;
|
|
122
|
+
const trimmed = headerValue.trim();
|
|
123
|
+
if (trimmed === '')
|
|
124
|
+
return undefined;
|
|
125
|
+
let ms;
|
|
126
|
+
if (/^\d+$/.test(trimmed)) {
|
|
127
|
+
ms = Number(trimmed) * 1000;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
const when = Date.parse(trimmed);
|
|
131
|
+
if (Number.isNaN(when))
|
|
132
|
+
return undefined;
|
|
133
|
+
ms = when - Date.now();
|
|
134
|
+
}
|
|
135
|
+
// A non-positive Retry-After (e.g. "0" or a past HTTP-date) must NOT short-
|
|
136
|
+
// circuit the backoff to zero — treat it as absent so the caller falls back
|
|
137
|
+
// to jitter and the loop can't busy-poll until timeout.
|
|
138
|
+
return ms > 0 ? ms : undefined;
|
|
139
|
+
}
|
|
140
|
+
// Cancellable sleep for poll loops. Resolves after `ms`, or rejects with
|
|
141
|
+
// `GislAbortError` if `signal` aborts. Resolves immediately for ms <= 0.
|
|
142
|
+
function cancellableSleep(ms, signal) {
|
|
143
|
+
if (signal?.aborted)
|
|
144
|
+
return Promise.reject(new GislAbortError('waitForProbe aborted'));
|
|
145
|
+
if (ms <= 0)
|
|
146
|
+
return Promise.resolve();
|
|
147
|
+
return new Promise((resolve, reject) => {
|
|
148
|
+
const onAbort = () => {
|
|
149
|
+
clearTimeout(timer);
|
|
150
|
+
signal?.removeEventListener('abort', onAbort);
|
|
151
|
+
reject(new GislAbortError('waitForProbe aborted'));
|
|
152
|
+
};
|
|
153
|
+
const timer = setTimeout(() => {
|
|
154
|
+
signal?.removeEventListener('abort', onAbort);
|
|
155
|
+
resolve();
|
|
156
|
+
}, ms);
|
|
157
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
158
|
+
});
|
|
159
|
+
}
|
|
115
160
|
// Full-jitter exponential backoff: delay = random(0, base * 2^attemptIndex).
|
|
116
161
|
// AWS SDK guidance for shared-throttling sources like S3 — keeps competing
|
|
117
162
|
// clients from synchronising their retries.
|
|
@@ -1979,19 +2024,118 @@ export class GislClient {
|
|
|
1979
2024
|
/**
|
|
1980
2025
|
* Probe an uploaded file for workflow-readiness — detects corruption,
|
|
1981
2026
|
* unsupported codecs, and pre-assigns the processing class the server
|
|
1982
|
-
* would route the file to.
|
|
1983
|
-
*
|
|
2027
|
+
* would route the file to. For video uploads the probe also lands the
|
|
2028
|
+
* codec + duration the server needs to admit the parallel split, so
|
|
2029
|
+
* calling this (or {@link waitForProbe}) before workflow-create is the
|
|
2030
|
+
* structural unlock for the fast video path on the multipart flow.
|
|
1984
2031
|
*
|
|
1985
|
-
*
|
|
1986
|
-
*
|
|
1987
|
-
*
|
|
1988
|
-
*
|
|
2032
|
+
* Endpoint availability is `stable`. The probe runs asynchronously after
|
|
2033
|
+
* upload: until the result has landed, this returns `422`
|
|
2034
|
+
* `feature_not_available` (surfaced as {@link GislFeatureNotAvailableError})
|
|
2035
|
+
* — i.e. that 422 means "probe not landed yet", NOT "not implemented". Once
|
|
2036
|
+
* landed it returns a `200` with any `probeStatus`. Idempotent: probing the
|
|
2037
|
+
* same `fileId` twice returns the cached result. See {@link waitForProbe}
|
|
2038
|
+
* for a bounded poll that turns this into a single ready/gave-up answer.
|
|
1989
2039
|
*/
|
|
1990
|
-
async probeUpload(fileId) {
|
|
2040
|
+
async probeUpload(fileId, options = {}) {
|
|
1991
2041
|
return this.request('POST', `/api/uploads/${encodeURIComponent(fileId)}/probe`, {
|
|
1992
2042
|
deserialize: UploadProbeResponseFromJSON,
|
|
2043
|
+
signal: options.signal,
|
|
1993
2044
|
});
|
|
1994
2045
|
}
|
|
2046
|
+
/**
|
|
2047
|
+
* Bounded poll of {@link probeUpload} until the probe lands — the helper
|
|
2048
|
+
* frontends call between upload-complete and workflow-create so the server
|
|
2049
|
+
* sees the video's codec + duration and admits the ~3× parallel split.
|
|
2050
|
+
*
|
|
2051
|
+
* Loop (per the API wire contract):
|
|
2052
|
+
* - `422 feature_not_available` → probe not landed yet → keep polling
|
|
2053
|
+
* (exponential full-jitter backoff, honouring a `Retry-After` header when
|
|
2054
|
+
* present, clamped to the remaining budget).
|
|
2055
|
+
* - any `200` → STOP. Resolves `{ landed: true, probe }` regardless of
|
|
2056
|
+
* `probeStatus` (ok / corrupt / unsupported_codec / missing_metadata) —
|
|
2057
|
+
* the server + fan-out gate decide split-vs-single from the landed
|
|
2058
|
+
* metadata; the SDK does not interpret it.
|
|
2059
|
+
* - `5xx` (prober crash) → retry a couple of times, then give up.
|
|
2060
|
+
* - timeout → give up.
|
|
2061
|
+
*
|
|
2062
|
+
* **Never bounces:** on give-up (timeout / repeated 5xx / transport) it
|
|
2063
|
+
* resolves `{ landed: false, reason }` rather than throwing, so the caller
|
|
2064
|
+
* proceeds to create the workflow anyway (the server's size heuristic routes
|
|
2065
|
+
* it; worst case = today's single-task behaviour). Genuine failures —
|
|
2066
|
+
* `404 upload_not_found`, auth errors, or caller abort — DO propagate (they
|
|
2067
|
+
* are not "probe not ready"), so a real problem is never silently swallowed.
|
|
2068
|
+
*
|
|
2069
|
+
* `timeoutMs` bounds the OVERALL poll, checked between attempts; each
|
|
2070
|
+
* in-flight probe request is bounded by the client's own per-request timeout
|
|
2071
|
+
* (a hung request surfaces as a transient and the next deadline check gives
|
|
2072
|
+
* up). So a single slow probe may run up to one client-request-timeout before
|
|
2073
|
+
* the wait returns.
|
|
2074
|
+
*/
|
|
2075
|
+
async waitForProbe(fileId, options = {}) {
|
|
2076
|
+
const timeoutMs = sanitiseBaseMs(options.timeoutMs, 30_000);
|
|
2077
|
+
const signal = options.signal;
|
|
2078
|
+
const start = Date.now();
|
|
2079
|
+
const deadline = start + timeoutMs;
|
|
2080
|
+
const BASE_BACKOFF_MS = 250;
|
|
2081
|
+
const MAX_PROBER_RETRIES = 2;
|
|
2082
|
+
let attempt = 0;
|
|
2083
|
+
// Counts transient probe-call failures (5xx + transport + per-request
|
|
2084
|
+
// timeout) — repeated transients give up so the caller creates anyway
|
|
2085
|
+
// (never-bounce).
|
|
2086
|
+
let transientFailures = 0;
|
|
2087
|
+
for (;;) {
|
|
2088
|
+
if (signal?.aborted)
|
|
2089
|
+
throw new GislAbortError('waitForProbe aborted');
|
|
2090
|
+
const remainingBeforeAttempt = deadline - Date.now();
|
|
2091
|
+
if (remainingBeforeAttempt <= 0)
|
|
2092
|
+
return { landed: false, reason: 'timeout' };
|
|
2093
|
+
attempt += 1;
|
|
2094
|
+
options.onPoll?.({ attempt, elapsedMs: Date.now() - start });
|
|
2095
|
+
let retryAfterMs;
|
|
2096
|
+
try {
|
|
2097
|
+
const probe = await this.probeUpload(fileId, { signal });
|
|
2098
|
+
return { landed: true, probe };
|
|
2099
|
+
}
|
|
2100
|
+
catch (err) {
|
|
2101
|
+
// A CALLER abort always propagates (it is not "probe not ready").
|
|
2102
|
+
if (signal?.aborted) {
|
|
2103
|
+
throw err instanceof GislAbortError ? err : new GislAbortError('waitForProbe aborted');
|
|
2104
|
+
}
|
|
2105
|
+
if (err instanceof GislFeatureNotAvailableError) {
|
|
2106
|
+
// Not landed yet — keep polling.
|
|
2107
|
+
retryAfterMs = parseRetryAfterMs(err.responseHeaders?.['retry-after']);
|
|
2108
|
+
}
|
|
2109
|
+
else if ((err instanceof GislApiError && err.statusCode >= 500) ||
|
|
2110
|
+
err instanceof GislTimeoutError ||
|
|
2111
|
+
isRetryableNetworkError(err)) {
|
|
2112
|
+
// Transient probe-call failure — a 5xx, the client's own per-request
|
|
2113
|
+
// timeout, or a transport error. Retry a couple of times, then give
|
|
2114
|
+
// up (never-bounce: the caller creates anyway).
|
|
2115
|
+
transientFailures += 1;
|
|
2116
|
+
if (transientFailures > MAX_PROBER_RETRIES) {
|
|
2117
|
+
return { landed: false, reason: 'prober_error' };
|
|
2118
|
+
}
|
|
2119
|
+
retryAfterMs =
|
|
2120
|
+
err instanceof GislApiError
|
|
2121
|
+
? parseRetryAfterMs(err.responseHeaders?.['retry-after'])
|
|
2122
|
+
: undefined;
|
|
2123
|
+
}
|
|
2124
|
+
else {
|
|
2125
|
+
// 404 upload_not_found, auth, validation, or any other typed/unexpected
|
|
2126
|
+
// error is a real failure, not "probe not ready" — propagate.
|
|
2127
|
+
throw err;
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
const remaining = deadline - Date.now();
|
|
2131
|
+
if (remaining <= 0)
|
|
2132
|
+
return { landed: false, reason: 'timeout' };
|
|
2133
|
+
const backoff = retryAfterMs ?? fullJitterDelay(BASE_BACKOFF_MS, attempt - 1);
|
|
2134
|
+
await cancellableSleep(Math.min(backoff, remaining), signal);
|
|
2135
|
+
if (Date.now() >= deadline)
|
|
2136
|
+
return { landed: false, reason: 'timeout' };
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
1995
2139
|
/**
|
|
1996
2140
|
* Probe N uploaded files in parallel and partition the results by
|
|
1997
2141
|
* outcome. Returns `{ ok, rejected, errors }` so the caller can
|
|
@@ -68,6 +68,7 @@ export interface ResolveCompressOptionsOutput {
|
|
|
68
68
|
* @internal — exported for unit tests.
|
|
69
69
|
*/
|
|
70
70
|
export declare function _parseTargetSize(value: unknown): number;
|
|
71
|
+
export declare const KNOWN_WIRE_FIELDS: Readonly<Record<PresetMedia, ReadonlySet<string>>>;
|
|
71
72
|
/**
|
|
72
73
|
* Resolve the wire payload + introspection projection for a compress
|
|
73
74
|
* operation call. Throws {@link GislConfigError} before any network
|
|
@@ -300,7 +300,10 @@ function mergeLayer(acc, layer, source) {
|
|
|
300
300
|
// ---------------------------------------------------------------------------
|
|
301
301
|
// Validations on the merged wire payload
|
|
302
302
|
// ---------------------------------------------------------------------------
|
|
303
|
-
|
|
303
|
+
// Exported so the wire-key conformance guard (tests/unit/wire-key-conformance.test.ts)
|
|
304
|
+
// can pin this hand-maintained allowlist to the generated contract metadata: every
|
|
305
|
+
// field the resolver may emit MUST be a real contract option key for `compress`.
|
|
306
|
+
export const KNOWN_WIRE_FIELDS = Object.freeze({
|
|
304
307
|
image: new Set(['mode', 'quality', 'metadata', 'icc_profile', 'progressive', 'output_format']),
|
|
305
308
|
audio: new Set(['bitrate', 'channels', 'sample_rate', 'normalize', 'trim_start', 'trim_end']),
|
|
306
309
|
video: new Set(['codec', 'encoding_mode', 'crf', 'target_size_bytes', 'preset', 'width', 'height', 'fit', 'fps', 'faststart', 'audio_codec', 'audio_bitrate', 'trim_start', 'trim_end']),
|
package/dist/file-first.d.ts
CHANGED
|
@@ -466,7 +466,7 @@ export declare class FilesRecipe {
|
|
|
466
466
|
* lowering builds an internal Recipe that throws the same `GislConfigError`.
|
|
467
467
|
*/
|
|
468
468
|
compress(optimize?: OptimizeFor, options?: Record<string, unknown>): FilesRecipe;
|
|
469
|
-
/** Change every input's format. `format` lowers
|
|
469
|
+
/** Change every input's format. `format` lowers to the contract `output_format` wire key (via {@link Recipe.convert}), NOT `format`. */
|
|
470
470
|
convert(format: string, options?: Record<string, unknown>): FilesRecipe;
|
|
471
471
|
/** Generate a preview of every input. Omitted dimensions are dropped from the wire options. */
|
|
472
472
|
thumbnail(options?: {
|
package/dist/file-first.js
CHANGED
|
@@ -785,7 +785,7 @@ export class FilesRecipe {
|
|
|
785
785
|
compress(optimize, options = {}) {
|
|
786
786
|
return this.withStep(this.baseRecipe().compress(optimize, options));
|
|
787
787
|
}
|
|
788
|
-
/** Change every input's format. `format` lowers
|
|
788
|
+
/** Change every input's format. `format` lowers to the contract `output_format` wire key (via {@link Recipe.convert}), NOT `format`. */
|
|
789
789
|
convert(format, options = {}) {
|
|
790
790
|
return this.withStep(this.baseRecipe().convert(format, options));
|
|
791
791
|
}
|
package/dist/index.core.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { GislClient, DEFAULT_MULTIPART_FIRST_CHUNK_SIZE } from './client.js';
|
|
2
2
|
export { parseSseStream } from './sse.js';
|
|
3
|
-
export type { CreditsUsageOptions, ListWorkflowsOptions, GetSchemaOptions, GetSchemaResult, PreflightClipError, PreflightClipsResult, GislClientConfig, GislSseEvent, 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';
|
|
3
|
+
export type { CreditsUsageOptions, ListWorkflowsOptions, GetSchemaOptions, GetSchemaResult, PreflightClipError, PreflightClipsResult, ProbeWaitOptions, ProbeWaitResult, GislClientConfig, GislSseEvent, 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
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, GislResultNotReadyError, } from './errors.js';
|
package/dist/types.d.ts
CHANGED
|
@@ -287,6 +287,43 @@ export interface WaitOptions {
|
|
|
287
287
|
/** Called after each poll with current status */
|
|
288
288
|
onPoll?: (status: string) => void;
|
|
289
289
|
}
|
|
290
|
+
export interface ProbeWaitOptions {
|
|
291
|
+
/**
|
|
292
|
+
* Overall wall-clock bound for the poll loop in ms (default: 30000). On
|
|
293
|
+
* elapse the loop gives up and resolves `{ landed: false, reason: 'timeout' }`
|
|
294
|
+
* — it never throws for a slow probe (the caller then creates anyway).
|
|
295
|
+
*/
|
|
296
|
+
timeoutMs?: number;
|
|
297
|
+
/** Abort the wait early; aborting rejects the promise with `GislAbortError`. */
|
|
298
|
+
signal?: AbortSignal;
|
|
299
|
+
/**
|
|
300
|
+
* Fires once per poll attempt — drive an "analysing video…" UI in the gap
|
|
301
|
+
* between upload-complete and workflow-create. `attempt` is 1-based;
|
|
302
|
+
* `elapsedMs` is wall-clock since the wait started.
|
|
303
|
+
*/
|
|
304
|
+
onPoll?: (info: {
|
|
305
|
+
attempt: number;
|
|
306
|
+
elapsedMs: number;
|
|
307
|
+
}) => void;
|
|
308
|
+
}
|
|
309
|
+
export interface ProbeWaitResult {
|
|
310
|
+
/**
|
|
311
|
+
* True iff the probe landed — i.e. `POST /api/uploads/{id}/probe` returned
|
|
312
|
+
* 200 (ANY `probeStatus`: ok / corrupt / unsupported_codec / missing_metadata).
|
|
313
|
+
* The caller proceeds to create the workflow either way; a landed probe lets
|
|
314
|
+
* the server admit the parallel video split.
|
|
315
|
+
*/
|
|
316
|
+
landed: boolean;
|
|
317
|
+
/** The landed probe response — present iff `landed`. */
|
|
318
|
+
probe?: UploadProbeResponse;
|
|
319
|
+
/**
|
|
320
|
+
* Why the wait gave up WITHOUT a landed probe — present iff `!landed`.
|
|
321
|
+
* `timeout` = the bound elapsed; `prober_error` = repeated 5xx from the
|
|
322
|
+
* prober. In both cases the caller should create anyway (never-bounce); the
|
|
323
|
+
* server's size heuristic routes the job (single-task worst case).
|
|
324
|
+
*/
|
|
325
|
+
reason?: 'timeout' | 'prober_error';
|
|
326
|
+
}
|
|
290
327
|
export type GislSseEvent = {
|
|
291
328
|
event: typeof SseEventType.operation_progress;
|
|
292
329
|
data: SseOperationProgressData;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@giveitsmaller/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Node.js SDK for the GISL (Give It Smaller) file compression and processing API",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"node": ">=18"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@giveitsmaller/contracts": "^0.
|
|
34
|
+
"@giveitsmaller/contracts": "^0.18.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/node": "^22",
|