@tinify-dev/client 0.1.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.
@@ -0,0 +1,219 @@
1
+ /** Default API origin. Override with `baseUrl` or the `TINIFY_BASE_URL` env var. */
2
+ declare const DEFAULT_BASE_URL = "https://api.tinify.dev";
3
+ /** Maximum accepted image size in bytes (40 MiB), matching the server limit. */
4
+ declare const MAX_FILE_BYTES = 41943040;
5
+ /** Maximum number of files per batch. */
6
+ declare const MAX_BATCH_FILES = 200;
7
+ /** Batch statuses that will never change again. */
8
+ declare const BATCH_TERMINAL_STATUSES: readonly ["succeeded", "partially_succeeded", "failed", "canceled", "expired"];
9
+
10
+ /**
11
+ * Error codes the API is known to return. The union stays open (`string`)
12
+ * because the server may add codes without a client release.
13
+ */
14
+ type KnownTinifyErrorCode = "missing_authorization" | "invalid_api_key" | "missing_identity" | "insufficient_scope" | "account_unavailable" | "invalid_request" | "invalid_idempotency_key" | "idempotency_conflict" | "validation_failed" | "file_too_large" | "unsupported_media_type" | "invalid_quality_mode" | "lossless_not_supported" | "invalid_resize" | "invalid_crop" | "invalid_operation" | "quota_exhausted" | "too_many_upload_sessions" | "upload_session_storage_limit" | "batch_not_found" | "batch_too_large" | "batch_plan_required" | "batch_not_complete" | "batch_has_no_results" | "uploads_incomplete" | "duplicate_client_id" | "invalid_target_format" | "same_format_conversion" | "invalid_target_size" | "target_size_conflict" | "internal_error";
15
+ type TinifyErrorCode = KnownTinifyErrorCode | (string & {});
16
+ type QualityMode = "balanced" | "best_quality" | "lossless";
17
+ /**
18
+ * Output format for {@link TinifyClient.convert}.
19
+ *
20
+ * @beta The `/api/v1/images/convert` endpoint is rolling out server-side and
21
+ * may not be enabled for every account yet.
22
+ */
23
+ type TargetFormat = "avif" | "webp" | "jpeg" | "png";
24
+ type ImageOperation = "compress" | "resize" | "crop" | "convert";
25
+ /** Values of the X-RateLimit-* response headers. `reset` is epoch seconds. */
26
+ interface RateLimitInfo {
27
+ limit: number;
28
+ remaining: number;
29
+ reset: number;
30
+ }
31
+ /** Envelope returned by every client call. */
32
+ interface TinifyResponse<T> {
33
+ data: T;
34
+ /** Server request id (`request_id` body field or `X-Request-Id` header). */
35
+ requestId: string;
36
+ /** Parsed X-RateLimit-* headers, or `null` when the server omitted them. */
37
+ rateLimit: RateLimitInfo | null;
38
+ }
39
+ /** `data` object of a successful synchronous image operation. */
40
+ interface ImageResultData {
41
+ job_id: string;
42
+ operation?: ImageOperation;
43
+ status: "succeeded";
44
+ /**
45
+ * `true` when the result is smaller than the input, `false` when the API
46
+ * returned the original bytes because it could not shrink them, `null`
47
+ * when the concept does not apply (resize/crop).
48
+ */
49
+ optimized: boolean | null;
50
+ /**
51
+ * Whether the result met the requested byte budget. Present only when
52
+ * compress ran with `target_size_bytes`.
53
+ */
54
+ target_size_achieved?: boolean;
55
+ quality_mode?: string;
56
+ original_format?: string;
57
+ result_format?: string;
58
+ original_bytes: number;
59
+ result_bytes: number;
60
+ /** Positive means the result grew. */
61
+ byte_change_percent?: number;
62
+ width: number | null;
63
+ height: number | null;
64
+ duration_ms?: number;
65
+ /** Expires two hours after the operation completes. */
66
+ download_url: string;
67
+ expires_at: string;
68
+ }
69
+ /** GET /api/v1/usage response body. */
70
+ interface Usage {
71
+ plan: string;
72
+ period_start: string;
73
+ period_end: string;
74
+ included: number;
75
+ reserved: number;
76
+ used: number;
77
+ remaining: number;
78
+ }
79
+ interface CompressOptions {
80
+ quality_mode?: QualityMode;
81
+ /**
82
+ * Ask the encoder to aim for a result at or below this many bytes.
83
+ *
84
+ * @beta Depends on a server rollout; accounts without it receive
85
+ * `validation_failed` or the parameter is ignored.
86
+ */
87
+ target_size_bytes?: number;
88
+ }
89
+ interface ResizeOptions {
90
+ width?: number;
91
+ height?: number;
92
+ scale?: number;
93
+ keep_aspect_ratio?: boolean;
94
+ optimize?: boolean;
95
+ }
96
+ interface CropOptions {
97
+ x: number;
98
+ y: number;
99
+ width: number;
100
+ height: number;
101
+ }
102
+ /**
103
+ * Options for {@link TinifyClient.convert}.
104
+ *
105
+ * @beta The convert endpoint is rolling out server-side.
106
+ */
107
+ interface ConvertOptions {
108
+ format: TargetFormat;
109
+ quality_mode?: QualityMode;
110
+ }
111
+ /** Per-call options accepted by every network method. */
112
+ interface RequestOptions {
113
+ /**
114
+ * Override the auto-generated Idempotency-Key (8-160 chars). The same key
115
+ * is reused for every retry of the call.
116
+ */
117
+ idempotencyKey?: string;
118
+ /** Abort the call (including retries and waits). */
119
+ signal?: AbortSignal;
120
+ /** Multipart filename override for buffer/blob inputs. */
121
+ filename?: string;
122
+ }
123
+ type BatchOperation = "compress" | "resize" | "crop" | "convert";
124
+ type BatchStatus = "awaiting_upload" | "queued" | "processing" | "succeeded" | "partially_succeeded" | "failed" | "canceled" | "expired";
125
+ type BatchTerminalStatus = (typeof BATCH_TERMINAL_STATUSES)[number];
126
+ type BatchContentType = "image/jpeg" | "image/png" | "image/webp" | "image/avif";
127
+ /** One manifest entry sent to POST /api/v1/batches. */
128
+ interface BatchFileManifestEntry {
129
+ /** Your identifier for the file; must be unique within the batch. */
130
+ client_id: string;
131
+ filename: string;
132
+ /** Exact size of the bytes you will PUT (1..41943040). */
133
+ size_bytes: number;
134
+ content_type: BatchContentType;
135
+ }
136
+ interface CreateBatchParams {
137
+ operation: BatchOperation;
138
+ /**
139
+ * Operation options, mirroring the synchronous endpoints:
140
+ *
141
+ * - `convert` requires {@link ConvertOptions.format}; files already in the
142
+ * target format fail per job with `same_format_conversion`.
143
+ * - `compress` accepts `quality_mode` and `target_size_bytes`; the target
144
+ * size is skipped per job when it is not smaller than that job's input.
145
+ */
146
+ options: CompressOptions | ResizeOptions | CropOptions | ConvertOptions | Record<string, unknown>;
147
+ files: BatchFileManifestEntry[];
148
+ }
149
+ /** Presigned upload slot returned when a batch is created. */
150
+ interface BatchUpload {
151
+ file_id: string;
152
+ client_id: string;
153
+ upload_url: string;
154
+ /** Send these headers verbatim on the PUT. Do NOT add Authorization. */
155
+ headers: Record<string, string>;
156
+ }
157
+ interface BatchUploadSession {
158
+ id: string;
159
+ status: "awaiting_upload";
160
+ expires_at: string;
161
+ uploads: BatchUpload[];
162
+ }
163
+ interface BatchFileError {
164
+ code: TinifyErrorCode;
165
+ }
166
+ interface BatchFile {
167
+ id: string;
168
+ client_id: string;
169
+ filename: string;
170
+ status: string;
171
+ original_bytes: number | null;
172
+ result_bytes: number | null;
173
+ optimized: boolean | null;
174
+ duration_ms: number | null;
175
+ error: BatchFileError | null;
176
+ /** Signed download URL; present only once the batch reached a result state. */
177
+ download_url: string | null;
178
+ }
179
+ interface Batch {
180
+ id: string;
181
+ operation: BatchOperation;
182
+ status: BatchStatus;
183
+ expires_at: string;
184
+ files: BatchFile[];
185
+ }
186
+ /** POST /api/v1/batches/{id}/commit response body. */
187
+ interface CommitBatchResult {
188
+ id: string;
189
+ status: BatchStatus;
190
+ }
191
+ interface UploadBatchFilesOptions {
192
+ /** Parallel presigned PUTs. Default 4. */
193
+ concurrency?: number;
194
+ signal?: AbortSignal;
195
+ }
196
+ interface WaitForBatchOptions {
197
+ /** First poll delay in milliseconds. Default 1000. */
198
+ pollIntervalMs?: number;
199
+ /** Poll delay ceiling in milliseconds. Default 10000. */
200
+ maxPollIntervalMs?: number;
201
+ /** Total waiting budget in milliseconds. Default 600000 (10 minutes). */
202
+ timeoutMs?: number;
203
+ signal?: AbortSignal;
204
+ }
205
+ type FetchFunction = (input: string | URL, init?: RequestInit) => Promise<Response>;
206
+ interface TinifyClientOptions {
207
+ /** API key (`tnf_live_*` or `tnf_test_*`). Falls back to TINIFY_API_KEY. */
208
+ apiKey?: string;
209
+ /** API origin. Falls back to TINIFY_BASE_URL, then https://api.tinify.dev. */
210
+ baseUrl?: string;
211
+ /** Retries after the initial attempt for 429/503/network failures. Default 3. */
212
+ maxRetries?: number;
213
+ /** Per-attempt timeout in milliseconds. Default 60000. */
214
+ timeoutMs?: number;
215
+ /** Injectable fetch implementation (used for testing and custom agents). */
216
+ fetch?: FetchFunction;
217
+ }
218
+
219
+ export { type BatchUploadSession as B, type CompressOptions as C, DEFAULT_BASE_URL as D, type FetchFunction as F, type ImageResultData as I, type KnownTinifyErrorCode as K, MAX_BATCH_FILES as M, type QualityMode as Q, type RequestOptions as R, type TargetFormat as T, type Usage as U, type WaitForBatchOptions as W, type TinifyClientOptions as a, type TinifyResponse as b, type ResizeOptions as c, type CropOptions as d, type ConvertOptions as e, type CreateBatchParams as f, type UploadBatchFilesOptions as g, type CommitBatchResult as h, type Batch as i, type TinifyErrorCode as j, type BatchStatus as k, type BatchTerminalStatus as l, BATCH_TERMINAL_STATUSES as m, type BatchContentType as n, type BatchFile as o, type BatchFileError as p, type BatchFileManifestEntry as q, type BatchOperation as r, type BatchUpload as s, type ImageOperation as t, MAX_FILE_BYTES as u, type RateLimitInfo as v };
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@tinify-dev/client",
3
+ "version": "0.1.0",
4
+ "description": "Zero-dependency TypeScript client for the Tinify.dev image API: compress, resize, crop, convert, batches, and usage.",
5
+ "license": "MIT",
6
+ "author": "Stian Larsen",
7
+ "type": "module",
8
+ "sideEffects": false,
9
+ "engines": {
10
+ "node": ">=20"
11
+ },
12
+ "bin": {
13
+ "tinify-dev": "dist/cli.js"
14
+ },
15
+ "main": "./dist/index.cjs",
16
+ "module": "./dist/index.js",
17
+ "types": "./dist/index.d.cts",
18
+ "exports": {
19
+ ".": {
20
+ "import": {
21
+ "types": "./dist/index.d.ts",
22
+ "default": "./dist/index.js"
23
+ },
24
+ "require": {
25
+ "types": "./dist/index.d.cts",
26
+ "default": "./dist/index.cjs"
27
+ }
28
+ },
29
+ "./package.json": "./package.json"
30
+ },
31
+ "files": [
32
+ "dist",
33
+ "CHANGELOG.md"
34
+ ],
35
+ "keywords": [
36
+ "tinify",
37
+ "image",
38
+ "compression",
39
+ "resize",
40
+ "crop",
41
+ "avif",
42
+ "webp",
43
+ "png",
44
+ "jpeg",
45
+ "api-client"
46
+ ],
47
+ "scripts": {
48
+ "build": "tsup",
49
+ "typecheck": "tsc --noEmit",
50
+ "test": "vitest run",
51
+ "test:watch": "vitest",
52
+ "check:publint": "publint",
53
+ "check:attw": "attw --pack ."
54
+ },
55
+ "devDependencies": {
56
+ "@arethetypeswrong/cli": "^0.16.4",
57
+ "@types/node": "^20.17.9",
58
+ "publint": "^0.2.12",
59
+ "tsup": "^8.3.5",
60
+ "typescript": "^5.6.3",
61
+ "undici": "^6.21.0",
62
+ "vitest": "^2.1.8"
63
+ }
64
+ }