Skip to main content

Quickstart

The SDK is file-first: you start from a file and call operations on it. The upload, workflow creation, and waiting are handled for you — one chain, one result.

Compress an image

import { gisl, OptimizeFor } from '@giveitsmaller/sdk';

const client = await gisl.create({ apiKey: 'REPLACE_ME_API_KEY' });

// Upload → compress → wait → resolve the download URL, in one chain.
const result = await client
.file('./photo.jpg')
.compress(OptimizeFor.Balanced)
.run({ maxWait: '5m' });

console.log('Compressed file:', result.url); // pre-signed download URL

That is the full round trip. Worth knowing:

  • Presets express intent. OptimizeFor.Size, .Balanced, and .Quality pick sensible options for the input's media type so you do not have to tune numbers. See Compress for per-call options.
  • run() waits up to 10 minutes by default — override with maxWait. For live progress instead of polling, subscribe to progress events.
  • Failures throw typed errors (GislApiError, GislValidationError, GislTimeoutError, …). See Errors.

Many files at once

The same chain runs over a list — each file is uploaded once and fanned out:

const many = await client
.files(['./a.jpg', './b.png'])
.compress(OptimizeFor.Balanced)
.run();

for (const artifact of many.artifacts) console.log(artifact.url);

Different recipes, one workflow — batch()

files() fans the same recipe across many inputs. When each input needs its own recipe (different ops / options), pass a list of single-input keyed recipes to batch([...]) — they run as one workflow and each result addresses back by the key you gave that file (the second argument to file()):

const hero = client.file('hero.jpg', 'hero').thumbnail({ width: 1200, height: 630 });
const avatar = client.file('avatar.jpg', 'avatar').thumbnail({ width: 256, height: 256 });

const result = await client.batch([hero, avatar]).run({ maxWait: '5m' });

console.log(result.byKey('hero').outputs[0].url);
console.log(result.byKey('avatar').outputs[0].url);
batch() v1 scope

Each entry must be a single-input keyed recipe (file(input, 'key').<op>(…)) with a unique non-empty key — multi-input recipes (merge / archive / overlay-watermark) are rejected with a GislConfigError before any upload. run() only in v1 (no submit() yet), and no cross-recipe upload dedupe (two entries sourcing the same file upload it twice). One failed entry lands in result.failed without sinking the rest.

Where next

  • Operations — compress, convert, thumbnail, merge, archive.
  • Workflows — how jobs, sources, and outputs fit together.
  • Errors — the error taxonomy and retry guidance.