@useknockout/node 0.0.4 → 0.0.5
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 +107 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -81,6 +81,31 @@ const out = await client.remove({ file: buf, filename: "input.jpg" });
|
|
|
81
81
|
const png = await client.removeUrl({ url: "https://example.com/cat.jpg" });
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
+
### New in 0.0.5 — presets
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
// Sticker — thick outline, transparent bg (iMessage / WhatsApp style)
|
|
88
|
+
const sticker = await client.sticker({ file: "./photo.jpg", strokeWidth: 24 });
|
|
89
|
+
|
|
90
|
+
// Outline — thin stroke around subject
|
|
91
|
+
const outlined = await client.outline({ file: "./photo.jpg", outlineColor: "#000000", outlineWidth: 4 });
|
|
92
|
+
|
|
93
|
+
// Smart crop — auto-crop to subject bbox + padding
|
|
94
|
+
const cropped = await client.smartCrop({ file: "./photo.jpg", padding: 32 });
|
|
95
|
+
|
|
96
|
+
// Shadow — drop shadow on a new background
|
|
97
|
+
const withShadow = await client.shadow({ file: "./photo.jpg", bgColor: "#F3F4F6" });
|
|
98
|
+
|
|
99
|
+
// Studio shot — e-commerce preset (centered subject, white bg, shadow, square)
|
|
100
|
+
const studio = await client.studioShot({ file: "./photo.jpg", aspect: "1:1" });
|
|
101
|
+
|
|
102
|
+
// Compare — before/after side-by-side image
|
|
103
|
+
const preview = await client.compare({ file: "./photo.jpg" });
|
|
104
|
+
|
|
105
|
+
// Mask — just the black/white mask for your own pipeline
|
|
106
|
+
const mask = await client.mask({ file: "./photo.jpg" });
|
|
107
|
+
```
|
|
108
|
+
|
|
84
109
|
## API
|
|
85
110
|
|
|
86
111
|
### `new Knockout(options?)`
|
|
@@ -152,6 +177,88 @@ Same as `removeBatch` but takes a JSON array of remote URLs.
|
|
|
152
177
|
|
|
153
178
|
Returns: `BatchResponse` with `url` in place of `filename` in each result.
|
|
154
179
|
|
|
180
|
+
### `client.mask(input)`
|
|
181
|
+
|
|
182
|
+
Return just the black/white alpha mask as a grayscale PNG/WebP.
|
|
183
|
+
|
|
184
|
+
| Field | Type | Description |
|
|
185
|
+
|---|---|---|
|
|
186
|
+
| `file` | `FileInput` | Image to process. |
|
|
187
|
+
| `format` | `"png" \| "webp"` | Default `"png"`. |
|
|
188
|
+
|
|
189
|
+
Returns: `Buffer` of a grayscale image (0 = bg, 255 = subject).
|
|
190
|
+
|
|
191
|
+
### `client.smartCrop(input)`
|
|
192
|
+
|
|
193
|
+
Auto-crop to the subject's tight bounding box + padding.
|
|
194
|
+
|
|
195
|
+
| Field | Type | Description |
|
|
196
|
+
|---|---|---|
|
|
197
|
+
| `file` | `FileInput` | Image to process. |
|
|
198
|
+
| `padding` | `number` | Padding in pixels. Default `24`. |
|
|
199
|
+
| `transparent` | `boolean` | `true` → transparent cutout. `false` → cropped from original. Default `true`. |
|
|
200
|
+
| `format` | `"png" \| "webp" \| "jpg"` | Default `"png"` (or `"jpg"` when `transparent=false`). |
|
|
201
|
+
|
|
202
|
+
### `client.shadow(input)`
|
|
203
|
+
|
|
204
|
+
Composite subject onto a new background with a configurable drop shadow.
|
|
205
|
+
|
|
206
|
+
| Field | Type | Description |
|
|
207
|
+
|---|---|---|
|
|
208
|
+
| `file` | `FileInput` | Image to process. |
|
|
209
|
+
| `bgColor` | `string` | Hex color. Default `"#FFFFFF"`. |
|
|
210
|
+
| `bgUrl` | `string` | Remote URL. Takes precedence over `bgColor`. |
|
|
211
|
+
| `shadowColor` | `string` | Default `"#000000"`. |
|
|
212
|
+
| `shadowOffsetX` | `number` | Default `8`. |
|
|
213
|
+
| `shadowOffsetY` | `number` | Default `12`. |
|
|
214
|
+
| `shadowBlur` | `number` | Default `14`. |
|
|
215
|
+
| `shadowOpacity` | `number` | 0.0–1.0. Default `0.45`. |
|
|
216
|
+
| `format` | `"png" \| "webp" \| "jpg"` | Default `"png"`. |
|
|
217
|
+
|
|
218
|
+
### `client.sticker(input)`
|
|
219
|
+
|
|
220
|
+
Subject with a thick outline on transparent background — sticker style.
|
|
221
|
+
|
|
222
|
+
| Field | Type | Description |
|
|
223
|
+
|---|---|---|
|
|
224
|
+
| `file` | `FileInput` | Image to process. |
|
|
225
|
+
| `strokeColor` | `string` | Default `"#FFFFFF"`. |
|
|
226
|
+
| `strokeWidth` | `number` | Pixels. Default `20`, capped at `80`. |
|
|
227
|
+
| `format` | `"png" \| "webp"` | Default `"png"`. |
|
|
228
|
+
|
|
229
|
+
### `client.outline(input)`
|
|
230
|
+
|
|
231
|
+
Subject with a thin outline on transparent background.
|
|
232
|
+
|
|
233
|
+
| Field | Type | Description |
|
|
234
|
+
|---|---|---|
|
|
235
|
+
| `file` | `FileInput` | Image to process. |
|
|
236
|
+
| `outlineColor` | `string` | Default `"#000000"`. |
|
|
237
|
+
| `outlineWidth` | `number` | Pixels. Default `4`, capped at `60`. |
|
|
238
|
+
| `format` | `"png" \| "webp"` | Default `"png"`. |
|
|
239
|
+
|
|
240
|
+
### `client.studioShot(input)`
|
|
241
|
+
|
|
242
|
+
E-commerce preset: cutout + centered on canvas + optional drop shadow + standardized aspect ratio.
|
|
243
|
+
|
|
244
|
+
| Field | Type | Description |
|
|
245
|
+
|---|---|---|
|
|
246
|
+
| `file` | `FileInput` | Image to process. |
|
|
247
|
+
| `bgColor` | `string` | Canvas color. Default `"#FFFFFF"`. |
|
|
248
|
+
| `aspect` | `string` | `"W:H"` format, e.g. `"1:1"`, `"4:5"`, `"16:9"`. Default `"1:1"`. |
|
|
249
|
+
| `padding` | `number` | Padding in pixels. Default `48`. |
|
|
250
|
+
| `shadow` | `boolean` | Include drop shadow. Default `true`. |
|
|
251
|
+
| `format` | `"png" \| "webp" \| "jpg"` | Default `"jpg"`. |
|
|
252
|
+
|
|
253
|
+
### `client.compare(input)`
|
|
254
|
+
|
|
255
|
+
Before/after side-by-side preview — original on the left, transparent cutout (on a checkerboard) on the right.
|
|
256
|
+
|
|
257
|
+
| Field | Type | Description |
|
|
258
|
+
|---|---|---|
|
|
259
|
+
| `file` | `FileInput` | Image to process. |
|
|
260
|
+
| `format` | `"png" \| "webp"` | Default `"png"`. |
|
|
261
|
+
|
|
155
262
|
### `client.health()`
|
|
156
263
|
|
|
157
264
|
Returns: `Promise<{ status: string; model: string }>`. No auth required.
|
package/dist/index.cjs
CHANGED
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":["readFile","basename"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @useknockout/node — official TypeScript / Node.js client for the useknockout API.\n *\n * Quick start:\n *\n * import { Knockout } from \"@useknockout/node\";\n *\n * const client = new Knockout({ token: process.env.KNOCKOUT_TOKEN! });\n * const png = await client.remove({ file: \"./input.jpg\" }); // Buffer of PNG bytes\n * await writeFile(\"out.png\", png);\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { basename } from \"node:path\";\n\nexport const DEFAULT_BASE_URL = \"https://useknockout--api.modal.run\";\nconst SDK_VERSION = \"0.0.4\";\n\nexport type OutputFormat = \"png\" | \"webp\";\nexport type OpaqueFormat = \"png\" | \"webp\" | \"jpg\";\n\ntype FileInput = string | Buffer | Blob | ArrayBuffer | Uint8Array;\n\nexport interface KnockoutOptions {\n /** API bearer token. Required unless your self-hosted instance has no auth. */\n token?: string;\n /** Override the API base URL. Defaults to the hosted endpoint. */\n baseUrl?: string;\n /** Per-request timeout in milliseconds. Default 60_000. */\n timeoutMs?: number;\n /** Custom fetch (useful for edge runtimes / polyfills). Defaults to global fetch. */\n fetch?: typeof fetch;\n}\n\nexport interface RemoveInput {\n /** Local file path, Buffer, Blob, or ArrayBuffer of the image. */\n file: string | Buffer | Blob | ArrayBuffer | Uint8Array;\n /** Optional filename — inferred from path when `file` is a string. */\n filename?: string;\n /** Output format. Default \"png\". */\n format?: OutputFormat;\n}\n\nexport interface RemoveUrlInput {\n /** Remote URL of the image to process. */\n url: string;\n /** Output format. Default \"png\". */\n format?: OutputFormat;\n}\n\nexport interface ReplaceBgInput {\n /** Local file path, Buffer, Blob, or ArrayBuffer of the foreground image. */\n file: string | Buffer | Blob | ArrayBuffer | Uint8Array;\n /** Optional filename — inferred from path when `file` is a string. */\n filename?: string;\n /** Hex color for the new background. Default \"#FFFFFF\". Ignored if `bgUrl` is set. */\n bgColor?: string;\n /** Remote URL of an image to use as the new background. Takes precedence over `bgColor`. */\n bgUrl?: string;\n /** Output format. \"jpg\" is smallest. Default \"png\". */\n format?: OpaqueFormat;\n}\n\nexport interface BatchInput {\n /** Array of local paths / buffers / blobs. Up to 10. */\n files: Array<string | Buffer | Blob | ArrayBuffer | Uint8Array>;\n /** Optional filenames aligned to `files`. */\n filenames?: string[];\n /** Output format for each image. Default \"png\". */\n format?: OutputFormat;\n}\n\nexport interface BatchUrlInput {\n /** Remote URLs to process. Up to 10. */\n urls: string[];\n /** Output format for each image. Default \"png\". */\n format?: OutputFormat;\n}\n\nexport interface BatchResultItem {\n filename?: string;\n url?: string;\n success: boolean;\n format?: OutputFormat;\n size_bytes?: number;\n data_base64?: string;\n error?: string;\n}\n\nexport interface BatchResponse {\n count: number;\n format: OutputFormat;\n results: BatchResultItem[];\n}\n\nexport interface MaskInput {\n file: FileInput;\n filename?: string;\n format?: OutputFormat;\n}\n\nexport interface SmartCropInput {\n file: FileInput;\n filename?: string;\n /** Padding around the subject bbox, in pixels. Default 24. */\n padding?: number;\n /** Return transparent cutout (true) or cropped region from original (false). Default true. */\n transparent?: boolean;\n format?: OpaqueFormat;\n}\n\nexport interface ShadowInput {\n file: FileInput;\n filename?: string;\n bgColor?: string;\n bgUrl?: string;\n shadowColor?: string;\n shadowOffsetX?: number;\n shadowOffsetY?: number;\n shadowBlur?: number;\n shadowOpacity?: number;\n format?: OpaqueFormat;\n}\n\nexport interface StickerInput {\n file: FileInput;\n filename?: string;\n /** Hex color for the outline. Default \"#FFFFFF\". */\n strokeColor?: string;\n /** Outline width in pixels. Default 20. */\n strokeWidth?: number;\n format?: OutputFormat;\n}\n\nexport interface OutlineInput {\n file: FileInput;\n filename?: string;\n /** Hex color for the outline. Default \"#000000\". */\n outlineColor?: string;\n /** Outline width in pixels. Default 4. */\n outlineWidth?: number;\n format?: OutputFormat;\n}\n\nexport interface StudioShotInput {\n file: FileInput;\n filename?: string;\n bgColor?: string;\n /** e.g. \"1:1\", \"4:5\", \"16:9\". Default \"1:1\". */\n aspect?: string;\n padding?: number;\n shadow?: boolean;\n format?: OpaqueFormat;\n}\n\nexport interface CompareInput {\n file: FileInput;\n filename?: string;\n format?: OutputFormat;\n}\n\nexport interface HealthResponse {\n status: string;\n model: string;\n}\n\n/**\n * Error thrown when the API returns a non-2xx response.\n */\nexport class KnockoutError extends Error {\n public readonly status: number;\n public readonly code: \"auth\" | \"rate_limit\" | \"bad_request\" | \"payload_too_large\" | \"server\" | \"unknown\";\n public readonly body: string;\n\n constructor(status: number, body: string) {\n const code = KnockoutError.classify(status);\n super(`Knockout API error ${status} (${code}): ${body || \"no body\"}`);\n this.name = \"KnockoutError\";\n this.status = status;\n this.code = code;\n this.body = body;\n }\n\n private static classify(status: number): KnockoutError[\"code\"] {\n if (status === 401 || status === 403) return \"auth\";\n if (status === 429) return \"rate_limit\";\n if (status === 413) return \"payload_too_large\";\n if (status >= 400 && status < 500) return \"bad_request\";\n if (status >= 500) return \"server\";\n return \"unknown\";\n }\n}\n\n/**\n * useknockout API client.\n *\n * All methods return a `Buffer` (Node) of the processed image bytes.\n * Use `.toString(\"base64\")` or `writeFile(path, buf)` to persist.\n */\nexport class Knockout {\n private readonly baseUrl: string;\n private readonly token: string | undefined;\n private readonly timeoutMs: number;\n private readonly fetchImpl: typeof fetch;\n\n constructor(options: KnockoutOptions = {}) {\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.token = options.token;\n this.timeoutMs = options.timeoutMs ?? 60_000;\n const fetchRef = options.fetch ?? globalThis.fetch;\n if (!fetchRef) {\n throw new Error(\n \"Global fetch is unavailable. Provide `options.fetch` or use Node 18+.\"\n );\n }\n this.fetchImpl = fetchRef.bind(globalThis);\n }\n\n /** Hit GET /health — no auth required. */\n async health(): Promise<HealthResponse> {\n const res = await this.request(\"GET\", \"/health\");\n const body = await res.text();\n if (!res.ok) throw new KnockoutError(res.status, body);\n return JSON.parse(body) as HealthResponse;\n }\n\n /**\n * Remove the background from an image, returning the cleaned PNG/WebP bytes.\n *\n * @example\n * const png = await client.remove({ file: \"./input.jpg\" });\n */\n async remove(input: RemoveInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob(input);\n\n const form = new FormData();\n form.append(\"file\", blob, filename);\n\n const res = await this.request(\"POST\", `/remove?format=${format}`, {\n body: form,\n });\n\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Remove the background from a remote URL, returning the cleaned PNG/WebP bytes.\n *\n * @example\n * const png = await client.removeUrl({ url: \"https://example.com/cat.jpg\" });\n */\n async removeUrl(input: RemoveUrlInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const res = await this.request(\"POST\", \"/remove-url\", {\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ url: input.url, format }),\n });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Replace the background with a solid color or a remote image.\n *\n * @example Solid color\n * const jpg = await client.replaceBackground({ file: \"./cat.jpg\", bgColor: \"#FF5733\", format: \"jpg\" });\n *\n * @example Remote image as new background\n * const png = await client.replaceBackground({\n * file: \"./cat.jpg\",\n * bgUrl: \"https://example.com/beach.jpg\",\n * });\n */\n async replaceBackground(input: ReplaceBgInput): Promise<Buffer> {\n const format: OpaqueFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n\n const form = new FormData();\n form.append(\"file\", blob, filename);\n\n const params = new URLSearchParams({ format });\n if (input.bgUrl) params.set(\"bg_url\", input.bgUrl);\n if (input.bgColor) params.set(\"bg_color\", input.bgColor);\n\n const res = await this.request(\"POST\", `/replace-bg?${params.toString()}`, {\n body: form,\n });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Remove the background from up to 10 images in a single call.\n * Returns a JSON object with base64-encoded result bytes per image.\n *\n * @example\n * const batch = await client.removeBatch({\n * files: [\"./a.jpg\", \"./b.jpg\", \"./c.jpg\"],\n * format: \"png\",\n * });\n * for (const r of batch.results) {\n * if (r.success) await writeFile(r.filename!, Buffer.from(r.data_base64!, \"base64\"));\n * }\n */\n async removeBatch(input: BatchInput): Promise<BatchResponse> {\n const format: OutputFormat = input.format ?? \"png\";\n if (input.files.length === 0) throw new Error(\"At least one file required\");\n if (input.files.length > 10) throw new Error(\"Max 10 files per batch\");\n\n const form = new FormData();\n for (let i = 0; i < input.files.length; i++) {\n const name = input.filenames?.[i];\n const { blob, filename } = await toBlob({ file: input.files[i]!, filename: name });\n form.append(\"files\", blob, filename);\n }\n\n const res = await this.request(\"POST\", `/remove-batch?format=${format}`, {\n body: form,\n });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return (await res.json()) as BatchResponse;\n }\n\n /**\n * Return only the alpha mask as a grayscale PNG/WebP.\n * Useful when chaining into your own compositing pipeline.\n */\n async mask(input: MaskInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/mask\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Auto-crop to the subject's tight bounding box with configurable padding.\n * Returns either a transparent cutout or a cropped region from the original image.\n */\n async smartCrop(input: SmartCropInput): Promise<Buffer> {\n const transparent = input.transparent ?? true;\n const format: OpaqueFormat =\n (input.format as OpaqueFormat | undefined) ?? (transparent ? \"png\" : \"jpg\");\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n form.append(\"padding\", String(input.padding ?? 24));\n form.append(\"transparent\", transparent ? \"true\" : \"false\");\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/smart-crop\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Composite subject onto a new background with a configurable drop shadow.\n */\n async shadow(input: ShadowInput): Promise<Buffer> {\n const format: OpaqueFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n if (input.bgColor) form.append(\"bg_color\", input.bgColor);\n if (input.bgUrl) form.append(\"bg_url\", input.bgUrl);\n if (input.shadowColor) form.append(\"shadow_color\", input.shadowColor);\n if (input.shadowOffsetX !== undefined) form.append(\"shadow_offset_x\", String(input.shadowOffsetX));\n if (input.shadowOffsetY !== undefined) form.append(\"shadow_offset_y\", String(input.shadowOffsetY));\n if (input.shadowBlur !== undefined) form.append(\"shadow_blur\", String(input.shadowBlur));\n if (input.shadowOpacity !== undefined) form.append(\"shadow_opacity\", String(input.shadowOpacity));\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/shadow\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Sticker style — subject with a thick outline on transparent background.\n * Perfect for WhatsApp / iMessage / Telegram stickers.\n */\n async sticker(input: StickerInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n if (input.strokeColor) form.append(\"stroke_color\", input.strokeColor);\n if (input.strokeWidth !== undefined) form.append(\"stroke_width\", String(input.strokeWidth));\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/sticker\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Subject on transparent background with a thin configurable outline.\n */\n async outline(input: OutlineInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n if (input.outlineColor) form.append(\"outline_color\", input.outlineColor);\n if (input.outlineWidth !== undefined) form.append(\"outline_width\", String(input.outlineWidth));\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/outline\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * E-commerce preset — cutout + tight crop + centered + optional shadow on a standard aspect canvas.\n */\n async studioShot(input: StudioShotInput): Promise<Buffer> {\n const format: OpaqueFormat = input.format ?? \"jpg\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n if (input.bgColor) form.append(\"bg_color\", input.bgColor);\n if (input.aspect) form.append(\"aspect\", input.aspect);\n if (input.padding !== undefined) form.append(\"padding\", String(input.padding));\n if (input.shadow !== undefined) form.append(\"shadow\", input.shadow ? \"true\" : \"false\");\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/studio-shot\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Before/after side-by-side preview — original on left, transparent cutout (on a checkerboard) on right.\n */\n async compare(input: CompareInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/compare\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Remove the background from up to 10 remote image URLs in a single call.\n *\n * @example\n * const batch = await client.removeBatchUrl({\n * urls: [\"https://a.jpg\", \"https://b.jpg\"],\n * });\n */\n async removeBatchUrl(input: BatchUrlInput): Promise<BatchResponse> {\n const format: OutputFormat = input.format ?? \"png\";\n if (input.urls.length === 0) throw new Error(\"At least one URL required\");\n if (input.urls.length > 10) throw new Error(\"Max 10 URLs per batch\");\n\n const res = await this.request(\"POST\", \"/remove-batch-url\", {\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ urls: input.urls, format }),\n });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return (await res.json()) as BatchResponse;\n }\n\n private async request(\n method: \"GET\" | \"POST\",\n path: string,\n init: { headers?: Record<string, string>; body?: BodyInit } = {}\n ): Promise<Response> {\n const url = `${this.baseUrl}${path}`;\n const headers: Record<string, string> = {\n \"User-Agent\": `useknockout-node/${SDK_VERSION}`,\n ...(init.headers ?? {}),\n };\n if (this.token) headers[\"Authorization\"] = `Bearer ${this.token}`;\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n try {\n return await this.fetchImpl(url, {\n method,\n headers,\n body: init.body,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n }\n}\n\nasync function toBlob(\n input: { file: string | Buffer | Blob | ArrayBuffer | Uint8Array; filename?: string }\n): Promise<{ blob: Blob; filename: string }> {\n const { file } = input;\n const filename = input.filename ?? inferFilename(file);\n\n if (typeof file === \"string\") {\n const data = await readFile(file);\n return { blob: new Blob([new Uint8Array(data)]), filename };\n }\n if (file instanceof Blob) {\n return { blob: file, filename };\n }\n if (file instanceof ArrayBuffer) {\n return { blob: new Blob([new Uint8Array(file)]), filename };\n }\n if (file instanceof Uint8Array) {\n return { blob: new Blob([new Uint8Array(file)]), filename };\n }\n if (Buffer.isBuffer(file)) {\n return {\n blob: new Blob([new Uint8Array(file)]),\n filename,\n };\n }\n throw new TypeError(\"Unsupported `file` input. Provide a path, Buffer, Blob, ArrayBuffer, or Uint8Array.\");\n}\n\nfunction inferFilename(file: string | Buffer | Blob | ArrayBuffer | Uint8Array): string {\n if (typeof file === \"string\") return basename(file) || \"image\";\n return \"image\";\n}\n\nexport default Knockout;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["readFile","basename"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @useknockout/node — official TypeScript / Node.js client for the useknockout API.\n *\n * Quick start:\n *\n * import { Knockout } from \"@useknockout/node\";\n *\n * const client = new Knockout({ token: process.env.KNOCKOUT_TOKEN! });\n * const png = await client.remove({ file: \"./input.jpg\" }); // Buffer of PNG bytes\n * await writeFile(\"out.png\", png);\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { basename } from \"node:path\";\n\nexport const DEFAULT_BASE_URL = \"https://useknockout--api.modal.run\";\nconst SDK_VERSION = \"0.0.5\";\n\nexport type OutputFormat = \"png\" | \"webp\";\nexport type OpaqueFormat = \"png\" | \"webp\" | \"jpg\";\n\ntype FileInput = string | Buffer | Blob | ArrayBuffer | Uint8Array;\n\nexport interface KnockoutOptions {\n /** API bearer token. Required unless your self-hosted instance has no auth. */\n token?: string;\n /** Override the API base URL. Defaults to the hosted endpoint. */\n baseUrl?: string;\n /** Per-request timeout in milliseconds. Default 60_000. */\n timeoutMs?: number;\n /** Custom fetch (useful for edge runtimes / polyfills). Defaults to global fetch. */\n fetch?: typeof fetch;\n}\n\nexport interface RemoveInput {\n /** Local file path, Buffer, Blob, or ArrayBuffer of the image. */\n file: string | Buffer | Blob | ArrayBuffer | Uint8Array;\n /** Optional filename — inferred from path when `file` is a string. */\n filename?: string;\n /** Output format. Default \"png\". */\n format?: OutputFormat;\n}\n\nexport interface RemoveUrlInput {\n /** Remote URL of the image to process. */\n url: string;\n /** Output format. Default \"png\". */\n format?: OutputFormat;\n}\n\nexport interface ReplaceBgInput {\n /** Local file path, Buffer, Blob, or ArrayBuffer of the foreground image. */\n file: string | Buffer | Blob | ArrayBuffer | Uint8Array;\n /** Optional filename — inferred from path when `file` is a string. */\n filename?: string;\n /** Hex color for the new background. Default \"#FFFFFF\". Ignored if `bgUrl` is set. */\n bgColor?: string;\n /** Remote URL of an image to use as the new background. Takes precedence over `bgColor`. */\n bgUrl?: string;\n /** Output format. \"jpg\" is smallest. Default \"png\". */\n format?: OpaqueFormat;\n}\n\nexport interface BatchInput {\n /** Array of local paths / buffers / blobs. Up to 10. */\n files: Array<string | Buffer | Blob | ArrayBuffer | Uint8Array>;\n /** Optional filenames aligned to `files`. */\n filenames?: string[];\n /** Output format for each image. Default \"png\". */\n format?: OutputFormat;\n}\n\nexport interface BatchUrlInput {\n /** Remote URLs to process. Up to 10. */\n urls: string[];\n /** Output format for each image. Default \"png\". */\n format?: OutputFormat;\n}\n\nexport interface BatchResultItem {\n filename?: string;\n url?: string;\n success: boolean;\n format?: OutputFormat;\n size_bytes?: number;\n data_base64?: string;\n error?: string;\n}\n\nexport interface BatchResponse {\n count: number;\n format: OutputFormat;\n results: BatchResultItem[];\n}\n\nexport interface MaskInput {\n file: FileInput;\n filename?: string;\n format?: OutputFormat;\n}\n\nexport interface SmartCropInput {\n file: FileInput;\n filename?: string;\n /** Padding around the subject bbox, in pixels. Default 24. */\n padding?: number;\n /** Return transparent cutout (true) or cropped region from original (false). Default true. */\n transparent?: boolean;\n format?: OpaqueFormat;\n}\n\nexport interface ShadowInput {\n file: FileInput;\n filename?: string;\n bgColor?: string;\n bgUrl?: string;\n shadowColor?: string;\n shadowOffsetX?: number;\n shadowOffsetY?: number;\n shadowBlur?: number;\n shadowOpacity?: number;\n format?: OpaqueFormat;\n}\n\nexport interface StickerInput {\n file: FileInput;\n filename?: string;\n /** Hex color for the outline. Default \"#FFFFFF\". */\n strokeColor?: string;\n /** Outline width in pixels. Default 20. */\n strokeWidth?: number;\n format?: OutputFormat;\n}\n\nexport interface OutlineInput {\n file: FileInput;\n filename?: string;\n /** Hex color for the outline. Default \"#000000\". */\n outlineColor?: string;\n /** Outline width in pixels. Default 4. */\n outlineWidth?: number;\n format?: OutputFormat;\n}\n\nexport interface StudioShotInput {\n file: FileInput;\n filename?: string;\n bgColor?: string;\n /** e.g. \"1:1\", \"4:5\", \"16:9\". Default \"1:1\". */\n aspect?: string;\n padding?: number;\n shadow?: boolean;\n format?: OpaqueFormat;\n}\n\nexport interface CompareInput {\n file: FileInput;\n filename?: string;\n format?: OutputFormat;\n}\n\nexport interface HealthResponse {\n status: string;\n model: string;\n}\n\n/**\n * Error thrown when the API returns a non-2xx response.\n */\nexport class KnockoutError extends Error {\n public readonly status: number;\n public readonly code: \"auth\" | \"rate_limit\" | \"bad_request\" | \"payload_too_large\" | \"server\" | \"unknown\";\n public readonly body: string;\n\n constructor(status: number, body: string) {\n const code = KnockoutError.classify(status);\n super(`Knockout API error ${status} (${code}): ${body || \"no body\"}`);\n this.name = \"KnockoutError\";\n this.status = status;\n this.code = code;\n this.body = body;\n }\n\n private static classify(status: number): KnockoutError[\"code\"] {\n if (status === 401 || status === 403) return \"auth\";\n if (status === 429) return \"rate_limit\";\n if (status === 413) return \"payload_too_large\";\n if (status >= 400 && status < 500) return \"bad_request\";\n if (status >= 500) return \"server\";\n return \"unknown\";\n }\n}\n\n/**\n * useknockout API client.\n *\n * All methods return a `Buffer` (Node) of the processed image bytes.\n * Use `.toString(\"base64\")` or `writeFile(path, buf)` to persist.\n */\nexport class Knockout {\n private readonly baseUrl: string;\n private readonly token: string | undefined;\n private readonly timeoutMs: number;\n private readonly fetchImpl: typeof fetch;\n\n constructor(options: KnockoutOptions = {}) {\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.token = options.token;\n this.timeoutMs = options.timeoutMs ?? 60_000;\n const fetchRef = options.fetch ?? globalThis.fetch;\n if (!fetchRef) {\n throw new Error(\n \"Global fetch is unavailable. Provide `options.fetch` or use Node 18+.\"\n );\n }\n this.fetchImpl = fetchRef.bind(globalThis);\n }\n\n /** Hit GET /health — no auth required. */\n async health(): Promise<HealthResponse> {\n const res = await this.request(\"GET\", \"/health\");\n const body = await res.text();\n if (!res.ok) throw new KnockoutError(res.status, body);\n return JSON.parse(body) as HealthResponse;\n }\n\n /**\n * Remove the background from an image, returning the cleaned PNG/WebP bytes.\n *\n * @example\n * const png = await client.remove({ file: \"./input.jpg\" });\n */\n async remove(input: RemoveInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob(input);\n\n const form = new FormData();\n form.append(\"file\", blob, filename);\n\n const res = await this.request(\"POST\", `/remove?format=${format}`, {\n body: form,\n });\n\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Remove the background from a remote URL, returning the cleaned PNG/WebP bytes.\n *\n * @example\n * const png = await client.removeUrl({ url: \"https://example.com/cat.jpg\" });\n */\n async removeUrl(input: RemoveUrlInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const res = await this.request(\"POST\", \"/remove-url\", {\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ url: input.url, format }),\n });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Replace the background with a solid color or a remote image.\n *\n * @example Solid color\n * const jpg = await client.replaceBackground({ file: \"./cat.jpg\", bgColor: \"#FF5733\", format: \"jpg\" });\n *\n * @example Remote image as new background\n * const png = await client.replaceBackground({\n * file: \"./cat.jpg\",\n * bgUrl: \"https://example.com/beach.jpg\",\n * });\n */\n async replaceBackground(input: ReplaceBgInput): Promise<Buffer> {\n const format: OpaqueFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n\n const form = new FormData();\n form.append(\"file\", blob, filename);\n\n const params = new URLSearchParams({ format });\n if (input.bgUrl) params.set(\"bg_url\", input.bgUrl);\n if (input.bgColor) params.set(\"bg_color\", input.bgColor);\n\n const res = await this.request(\"POST\", `/replace-bg?${params.toString()}`, {\n body: form,\n });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Remove the background from up to 10 images in a single call.\n * Returns a JSON object with base64-encoded result bytes per image.\n *\n * @example\n * const batch = await client.removeBatch({\n * files: [\"./a.jpg\", \"./b.jpg\", \"./c.jpg\"],\n * format: \"png\",\n * });\n * for (const r of batch.results) {\n * if (r.success) await writeFile(r.filename!, Buffer.from(r.data_base64!, \"base64\"));\n * }\n */\n async removeBatch(input: BatchInput): Promise<BatchResponse> {\n const format: OutputFormat = input.format ?? \"png\";\n if (input.files.length === 0) throw new Error(\"At least one file required\");\n if (input.files.length > 10) throw new Error(\"Max 10 files per batch\");\n\n const form = new FormData();\n for (let i = 0; i < input.files.length; i++) {\n const name = input.filenames?.[i];\n const { blob, filename } = await toBlob({ file: input.files[i]!, filename: name });\n form.append(\"files\", blob, filename);\n }\n\n const res = await this.request(\"POST\", `/remove-batch?format=${format}`, {\n body: form,\n });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return (await res.json()) as BatchResponse;\n }\n\n /**\n * Return only the alpha mask as a grayscale PNG/WebP.\n * Useful when chaining into your own compositing pipeline.\n */\n async mask(input: MaskInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/mask\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Auto-crop to the subject's tight bounding box with configurable padding.\n * Returns either a transparent cutout or a cropped region from the original image.\n */\n async smartCrop(input: SmartCropInput): Promise<Buffer> {\n const transparent = input.transparent ?? true;\n const format: OpaqueFormat =\n (input.format as OpaqueFormat | undefined) ?? (transparent ? \"png\" : \"jpg\");\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n form.append(\"padding\", String(input.padding ?? 24));\n form.append(\"transparent\", transparent ? \"true\" : \"false\");\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/smart-crop\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Composite subject onto a new background with a configurable drop shadow.\n */\n async shadow(input: ShadowInput): Promise<Buffer> {\n const format: OpaqueFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n if (input.bgColor) form.append(\"bg_color\", input.bgColor);\n if (input.bgUrl) form.append(\"bg_url\", input.bgUrl);\n if (input.shadowColor) form.append(\"shadow_color\", input.shadowColor);\n if (input.shadowOffsetX !== undefined) form.append(\"shadow_offset_x\", String(input.shadowOffsetX));\n if (input.shadowOffsetY !== undefined) form.append(\"shadow_offset_y\", String(input.shadowOffsetY));\n if (input.shadowBlur !== undefined) form.append(\"shadow_blur\", String(input.shadowBlur));\n if (input.shadowOpacity !== undefined) form.append(\"shadow_opacity\", String(input.shadowOpacity));\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/shadow\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Sticker style — subject with a thick outline on transparent background.\n * Perfect for WhatsApp / iMessage / Telegram stickers.\n */\n async sticker(input: StickerInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n if (input.strokeColor) form.append(\"stroke_color\", input.strokeColor);\n if (input.strokeWidth !== undefined) form.append(\"stroke_width\", String(input.strokeWidth));\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/sticker\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Subject on transparent background with a thin configurable outline.\n */\n async outline(input: OutlineInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n if (input.outlineColor) form.append(\"outline_color\", input.outlineColor);\n if (input.outlineWidth !== undefined) form.append(\"outline_width\", String(input.outlineWidth));\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/outline\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * E-commerce preset — cutout + tight crop + centered + optional shadow on a standard aspect canvas.\n */\n async studioShot(input: StudioShotInput): Promise<Buffer> {\n const format: OpaqueFormat = input.format ?? \"jpg\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n if (input.bgColor) form.append(\"bg_color\", input.bgColor);\n if (input.aspect) form.append(\"aspect\", input.aspect);\n if (input.padding !== undefined) form.append(\"padding\", String(input.padding));\n if (input.shadow !== undefined) form.append(\"shadow\", input.shadow ? \"true\" : \"false\");\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/studio-shot\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Before/after side-by-side preview — original on left, transparent cutout (on a checkerboard) on right.\n */\n async compare(input: CompareInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/compare\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Remove the background from up to 10 remote image URLs in a single call.\n *\n * @example\n * const batch = await client.removeBatchUrl({\n * urls: [\"https://a.jpg\", \"https://b.jpg\"],\n * });\n */\n async removeBatchUrl(input: BatchUrlInput): Promise<BatchResponse> {\n const format: OutputFormat = input.format ?? \"png\";\n if (input.urls.length === 0) throw new Error(\"At least one URL required\");\n if (input.urls.length > 10) throw new Error(\"Max 10 URLs per batch\");\n\n const res = await this.request(\"POST\", \"/remove-batch-url\", {\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ urls: input.urls, format }),\n });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return (await res.json()) as BatchResponse;\n }\n\n private async request(\n method: \"GET\" | \"POST\",\n path: string,\n init: { headers?: Record<string, string>; body?: BodyInit } = {}\n ): Promise<Response> {\n const url = `${this.baseUrl}${path}`;\n const headers: Record<string, string> = {\n \"User-Agent\": `useknockout-node/${SDK_VERSION}`,\n ...(init.headers ?? {}),\n };\n if (this.token) headers[\"Authorization\"] = `Bearer ${this.token}`;\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n try {\n return await this.fetchImpl(url, {\n method,\n headers,\n body: init.body,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n }\n}\n\nasync function toBlob(\n input: { file: string | Buffer | Blob | ArrayBuffer | Uint8Array; filename?: string }\n): Promise<{ blob: Blob; filename: string }> {\n const { file } = input;\n const filename = input.filename ?? inferFilename(file);\n\n if (typeof file === \"string\") {\n const data = await readFile(file);\n return { blob: new Blob([new Uint8Array(data)]), filename };\n }\n if (file instanceof Blob) {\n return { blob: file, filename };\n }\n if (file instanceof ArrayBuffer) {\n return { blob: new Blob([new Uint8Array(file)]), filename };\n }\n if (file instanceof Uint8Array) {\n return { blob: new Blob([new Uint8Array(file)]), filename };\n }\n if (Buffer.isBuffer(file)) {\n return {\n blob: new Blob([new Uint8Array(file)]),\n filename,\n };\n }\n throw new TypeError(\"Unsupported `file` input. Provide a path, Buffer, Blob, ArrayBuffer, or Uint8Array.\");\n}\n\nfunction inferFilename(file: string | Buffer | Blob | ArrayBuffer | Uint8Array): string {\n if (typeof file === \"string\") return basename(file) || \"image\";\n return \"image\";\n}\n\nexport default Knockout;\n"]}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @useknockout/node — official TypeScript / Node.js client for the useknockout API.\n *\n * Quick start:\n *\n * import { Knockout } from \"@useknockout/node\";\n *\n * const client = new Knockout({ token: process.env.KNOCKOUT_TOKEN! });\n * const png = await client.remove({ file: \"./input.jpg\" }); // Buffer of PNG bytes\n * await writeFile(\"out.png\", png);\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { basename } from \"node:path\";\n\nexport const DEFAULT_BASE_URL = \"https://useknockout--api.modal.run\";\nconst SDK_VERSION = \"0.0.4\";\n\nexport type OutputFormat = \"png\" | \"webp\";\nexport type OpaqueFormat = \"png\" | \"webp\" | \"jpg\";\n\ntype FileInput = string | Buffer | Blob | ArrayBuffer | Uint8Array;\n\nexport interface KnockoutOptions {\n /** API bearer token. Required unless your self-hosted instance has no auth. */\n token?: string;\n /** Override the API base URL. Defaults to the hosted endpoint. */\n baseUrl?: string;\n /** Per-request timeout in milliseconds. Default 60_000. */\n timeoutMs?: number;\n /** Custom fetch (useful for edge runtimes / polyfills). Defaults to global fetch. */\n fetch?: typeof fetch;\n}\n\nexport interface RemoveInput {\n /** Local file path, Buffer, Blob, or ArrayBuffer of the image. */\n file: string | Buffer | Blob | ArrayBuffer | Uint8Array;\n /** Optional filename — inferred from path when `file` is a string. */\n filename?: string;\n /** Output format. Default \"png\". */\n format?: OutputFormat;\n}\n\nexport interface RemoveUrlInput {\n /** Remote URL of the image to process. */\n url: string;\n /** Output format. Default \"png\". */\n format?: OutputFormat;\n}\n\nexport interface ReplaceBgInput {\n /** Local file path, Buffer, Blob, or ArrayBuffer of the foreground image. */\n file: string | Buffer | Blob | ArrayBuffer | Uint8Array;\n /** Optional filename — inferred from path when `file` is a string. */\n filename?: string;\n /** Hex color for the new background. Default \"#FFFFFF\". Ignored if `bgUrl` is set. */\n bgColor?: string;\n /** Remote URL of an image to use as the new background. Takes precedence over `bgColor`. */\n bgUrl?: string;\n /** Output format. \"jpg\" is smallest. Default \"png\". */\n format?: OpaqueFormat;\n}\n\nexport interface BatchInput {\n /** Array of local paths / buffers / blobs. Up to 10. */\n files: Array<string | Buffer | Blob | ArrayBuffer | Uint8Array>;\n /** Optional filenames aligned to `files`. */\n filenames?: string[];\n /** Output format for each image. Default \"png\". */\n format?: OutputFormat;\n}\n\nexport interface BatchUrlInput {\n /** Remote URLs to process. Up to 10. */\n urls: string[];\n /** Output format for each image. Default \"png\". */\n format?: OutputFormat;\n}\n\nexport interface BatchResultItem {\n filename?: string;\n url?: string;\n success: boolean;\n format?: OutputFormat;\n size_bytes?: number;\n data_base64?: string;\n error?: string;\n}\n\nexport interface BatchResponse {\n count: number;\n format: OutputFormat;\n results: BatchResultItem[];\n}\n\nexport interface MaskInput {\n file: FileInput;\n filename?: string;\n format?: OutputFormat;\n}\n\nexport interface SmartCropInput {\n file: FileInput;\n filename?: string;\n /** Padding around the subject bbox, in pixels. Default 24. */\n padding?: number;\n /** Return transparent cutout (true) or cropped region from original (false). Default true. */\n transparent?: boolean;\n format?: OpaqueFormat;\n}\n\nexport interface ShadowInput {\n file: FileInput;\n filename?: string;\n bgColor?: string;\n bgUrl?: string;\n shadowColor?: string;\n shadowOffsetX?: number;\n shadowOffsetY?: number;\n shadowBlur?: number;\n shadowOpacity?: number;\n format?: OpaqueFormat;\n}\n\nexport interface StickerInput {\n file: FileInput;\n filename?: string;\n /** Hex color for the outline. Default \"#FFFFFF\". */\n strokeColor?: string;\n /** Outline width in pixels. Default 20. */\n strokeWidth?: number;\n format?: OutputFormat;\n}\n\nexport interface OutlineInput {\n file: FileInput;\n filename?: string;\n /** Hex color for the outline. Default \"#000000\". */\n outlineColor?: string;\n /** Outline width in pixels. Default 4. */\n outlineWidth?: number;\n format?: OutputFormat;\n}\n\nexport interface StudioShotInput {\n file: FileInput;\n filename?: string;\n bgColor?: string;\n /** e.g. \"1:1\", \"4:5\", \"16:9\". Default \"1:1\". */\n aspect?: string;\n padding?: number;\n shadow?: boolean;\n format?: OpaqueFormat;\n}\n\nexport interface CompareInput {\n file: FileInput;\n filename?: string;\n format?: OutputFormat;\n}\n\nexport interface HealthResponse {\n status: string;\n model: string;\n}\n\n/**\n * Error thrown when the API returns a non-2xx response.\n */\nexport class KnockoutError extends Error {\n public readonly status: number;\n public readonly code: \"auth\" | \"rate_limit\" | \"bad_request\" | \"payload_too_large\" | \"server\" | \"unknown\";\n public readonly body: string;\n\n constructor(status: number, body: string) {\n const code = KnockoutError.classify(status);\n super(`Knockout API error ${status} (${code}): ${body || \"no body\"}`);\n this.name = \"KnockoutError\";\n this.status = status;\n this.code = code;\n this.body = body;\n }\n\n private static classify(status: number): KnockoutError[\"code\"] {\n if (status === 401 || status === 403) return \"auth\";\n if (status === 429) return \"rate_limit\";\n if (status === 413) return \"payload_too_large\";\n if (status >= 400 && status < 500) return \"bad_request\";\n if (status >= 500) return \"server\";\n return \"unknown\";\n }\n}\n\n/**\n * useknockout API client.\n *\n * All methods return a `Buffer` (Node) of the processed image bytes.\n * Use `.toString(\"base64\")` or `writeFile(path, buf)` to persist.\n */\nexport class Knockout {\n private readonly baseUrl: string;\n private readonly token: string | undefined;\n private readonly timeoutMs: number;\n private readonly fetchImpl: typeof fetch;\n\n constructor(options: KnockoutOptions = {}) {\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.token = options.token;\n this.timeoutMs = options.timeoutMs ?? 60_000;\n const fetchRef = options.fetch ?? globalThis.fetch;\n if (!fetchRef) {\n throw new Error(\n \"Global fetch is unavailable. Provide `options.fetch` or use Node 18+.\"\n );\n }\n this.fetchImpl = fetchRef.bind(globalThis);\n }\n\n /** Hit GET /health — no auth required. */\n async health(): Promise<HealthResponse> {\n const res = await this.request(\"GET\", \"/health\");\n const body = await res.text();\n if (!res.ok) throw new KnockoutError(res.status, body);\n return JSON.parse(body) as HealthResponse;\n }\n\n /**\n * Remove the background from an image, returning the cleaned PNG/WebP bytes.\n *\n * @example\n * const png = await client.remove({ file: \"./input.jpg\" });\n */\n async remove(input: RemoveInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob(input);\n\n const form = new FormData();\n form.append(\"file\", blob, filename);\n\n const res = await this.request(\"POST\", `/remove?format=${format}`, {\n body: form,\n });\n\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Remove the background from a remote URL, returning the cleaned PNG/WebP bytes.\n *\n * @example\n * const png = await client.removeUrl({ url: \"https://example.com/cat.jpg\" });\n */\n async removeUrl(input: RemoveUrlInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const res = await this.request(\"POST\", \"/remove-url\", {\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ url: input.url, format }),\n });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Replace the background with a solid color or a remote image.\n *\n * @example Solid color\n * const jpg = await client.replaceBackground({ file: \"./cat.jpg\", bgColor: \"#FF5733\", format: \"jpg\" });\n *\n * @example Remote image as new background\n * const png = await client.replaceBackground({\n * file: \"./cat.jpg\",\n * bgUrl: \"https://example.com/beach.jpg\",\n * });\n */\n async replaceBackground(input: ReplaceBgInput): Promise<Buffer> {\n const format: OpaqueFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n\n const form = new FormData();\n form.append(\"file\", blob, filename);\n\n const params = new URLSearchParams({ format });\n if (input.bgUrl) params.set(\"bg_url\", input.bgUrl);\n if (input.bgColor) params.set(\"bg_color\", input.bgColor);\n\n const res = await this.request(\"POST\", `/replace-bg?${params.toString()}`, {\n body: form,\n });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Remove the background from up to 10 images in a single call.\n * Returns a JSON object with base64-encoded result bytes per image.\n *\n * @example\n * const batch = await client.removeBatch({\n * files: [\"./a.jpg\", \"./b.jpg\", \"./c.jpg\"],\n * format: \"png\",\n * });\n * for (const r of batch.results) {\n * if (r.success) await writeFile(r.filename!, Buffer.from(r.data_base64!, \"base64\"));\n * }\n */\n async removeBatch(input: BatchInput): Promise<BatchResponse> {\n const format: OutputFormat = input.format ?? \"png\";\n if (input.files.length === 0) throw new Error(\"At least one file required\");\n if (input.files.length > 10) throw new Error(\"Max 10 files per batch\");\n\n const form = new FormData();\n for (let i = 0; i < input.files.length; i++) {\n const name = input.filenames?.[i];\n const { blob, filename } = await toBlob({ file: input.files[i]!, filename: name });\n form.append(\"files\", blob, filename);\n }\n\n const res = await this.request(\"POST\", `/remove-batch?format=${format}`, {\n body: form,\n });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return (await res.json()) as BatchResponse;\n }\n\n /**\n * Return only the alpha mask as a grayscale PNG/WebP.\n * Useful when chaining into your own compositing pipeline.\n */\n async mask(input: MaskInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/mask\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Auto-crop to the subject's tight bounding box with configurable padding.\n * Returns either a transparent cutout or a cropped region from the original image.\n */\n async smartCrop(input: SmartCropInput): Promise<Buffer> {\n const transparent = input.transparent ?? true;\n const format: OpaqueFormat =\n (input.format as OpaqueFormat | undefined) ?? (transparent ? \"png\" : \"jpg\");\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n form.append(\"padding\", String(input.padding ?? 24));\n form.append(\"transparent\", transparent ? \"true\" : \"false\");\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/smart-crop\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Composite subject onto a new background with a configurable drop shadow.\n */\n async shadow(input: ShadowInput): Promise<Buffer> {\n const format: OpaqueFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n if (input.bgColor) form.append(\"bg_color\", input.bgColor);\n if (input.bgUrl) form.append(\"bg_url\", input.bgUrl);\n if (input.shadowColor) form.append(\"shadow_color\", input.shadowColor);\n if (input.shadowOffsetX !== undefined) form.append(\"shadow_offset_x\", String(input.shadowOffsetX));\n if (input.shadowOffsetY !== undefined) form.append(\"shadow_offset_y\", String(input.shadowOffsetY));\n if (input.shadowBlur !== undefined) form.append(\"shadow_blur\", String(input.shadowBlur));\n if (input.shadowOpacity !== undefined) form.append(\"shadow_opacity\", String(input.shadowOpacity));\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/shadow\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Sticker style — subject with a thick outline on transparent background.\n * Perfect for WhatsApp / iMessage / Telegram stickers.\n */\n async sticker(input: StickerInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n if (input.strokeColor) form.append(\"stroke_color\", input.strokeColor);\n if (input.strokeWidth !== undefined) form.append(\"stroke_width\", String(input.strokeWidth));\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/sticker\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Subject on transparent background with a thin configurable outline.\n */\n async outline(input: OutlineInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n if (input.outlineColor) form.append(\"outline_color\", input.outlineColor);\n if (input.outlineWidth !== undefined) form.append(\"outline_width\", String(input.outlineWidth));\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/outline\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * E-commerce preset — cutout + tight crop + centered + optional shadow on a standard aspect canvas.\n */\n async studioShot(input: StudioShotInput): Promise<Buffer> {\n const format: OpaqueFormat = input.format ?? \"jpg\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n if (input.bgColor) form.append(\"bg_color\", input.bgColor);\n if (input.aspect) form.append(\"aspect\", input.aspect);\n if (input.padding !== undefined) form.append(\"padding\", String(input.padding));\n if (input.shadow !== undefined) form.append(\"shadow\", input.shadow ? \"true\" : \"false\");\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/studio-shot\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Before/after side-by-side preview — original on left, transparent cutout (on a checkerboard) on right.\n */\n async compare(input: CompareInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/compare\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Remove the background from up to 10 remote image URLs in a single call.\n *\n * @example\n * const batch = await client.removeBatchUrl({\n * urls: [\"https://a.jpg\", \"https://b.jpg\"],\n * });\n */\n async removeBatchUrl(input: BatchUrlInput): Promise<BatchResponse> {\n const format: OutputFormat = input.format ?? \"png\";\n if (input.urls.length === 0) throw new Error(\"At least one URL required\");\n if (input.urls.length > 10) throw new Error(\"Max 10 URLs per batch\");\n\n const res = await this.request(\"POST\", \"/remove-batch-url\", {\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ urls: input.urls, format }),\n });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return (await res.json()) as BatchResponse;\n }\n\n private async request(\n method: \"GET\" | \"POST\",\n path: string,\n init: { headers?: Record<string, string>; body?: BodyInit } = {}\n ): Promise<Response> {\n const url = `${this.baseUrl}${path}`;\n const headers: Record<string, string> = {\n \"User-Agent\": `useknockout-node/${SDK_VERSION}`,\n ...(init.headers ?? {}),\n };\n if (this.token) headers[\"Authorization\"] = `Bearer ${this.token}`;\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n try {\n return await this.fetchImpl(url, {\n method,\n headers,\n body: init.body,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n }\n}\n\nasync function toBlob(\n input: { file: string | Buffer | Blob | ArrayBuffer | Uint8Array; filename?: string }\n): Promise<{ blob: Blob; filename: string }> {\n const { file } = input;\n const filename = input.filename ?? inferFilename(file);\n\n if (typeof file === \"string\") {\n const data = await readFile(file);\n return { blob: new Blob([new Uint8Array(data)]), filename };\n }\n if (file instanceof Blob) {\n return { blob: file, filename };\n }\n if (file instanceof ArrayBuffer) {\n return { blob: new Blob([new Uint8Array(file)]), filename };\n }\n if (file instanceof Uint8Array) {\n return { blob: new Blob([new Uint8Array(file)]), filename };\n }\n if (Buffer.isBuffer(file)) {\n return {\n blob: new Blob([new Uint8Array(file)]),\n filename,\n };\n }\n throw new TypeError(\"Unsupported `file` input. Provide a path, Buffer, Blob, ArrayBuffer, or Uint8Array.\");\n}\n\nfunction inferFilename(file: string | Buffer | Blob | ArrayBuffer | Uint8Array): string {\n if (typeof file === \"string\") return basename(file) || \"image\";\n return \"image\";\n}\n\nexport default Knockout;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @useknockout/node — official TypeScript / Node.js client for the useknockout API.\n *\n * Quick start:\n *\n * import { Knockout } from \"@useknockout/node\";\n *\n * const client = new Knockout({ token: process.env.KNOCKOUT_TOKEN! });\n * const png = await client.remove({ file: \"./input.jpg\" }); // Buffer of PNG bytes\n * await writeFile(\"out.png\", png);\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { basename } from \"node:path\";\n\nexport const DEFAULT_BASE_URL = \"https://useknockout--api.modal.run\";\nconst SDK_VERSION = \"0.0.5\";\n\nexport type OutputFormat = \"png\" | \"webp\";\nexport type OpaqueFormat = \"png\" | \"webp\" | \"jpg\";\n\ntype FileInput = string | Buffer | Blob | ArrayBuffer | Uint8Array;\n\nexport interface KnockoutOptions {\n /** API bearer token. Required unless your self-hosted instance has no auth. */\n token?: string;\n /** Override the API base URL. Defaults to the hosted endpoint. */\n baseUrl?: string;\n /** Per-request timeout in milliseconds. Default 60_000. */\n timeoutMs?: number;\n /** Custom fetch (useful for edge runtimes / polyfills). Defaults to global fetch. */\n fetch?: typeof fetch;\n}\n\nexport interface RemoveInput {\n /** Local file path, Buffer, Blob, or ArrayBuffer of the image. */\n file: string | Buffer | Blob | ArrayBuffer | Uint8Array;\n /** Optional filename — inferred from path when `file` is a string. */\n filename?: string;\n /** Output format. Default \"png\". */\n format?: OutputFormat;\n}\n\nexport interface RemoveUrlInput {\n /** Remote URL of the image to process. */\n url: string;\n /** Output format. Default \"png\". */\n format?: OutputFormat;\n}\n\nexport interface ReplaceBgInput {\n /** Local file path, Buffer, Blob, or ArrayBuffer of the foreground image. */\n file: string | Buffer | Blob | ArrayBuffer | Uint8Array;\n /** Optional filename — inferred from path when `file` is a string. */\n filename?: string;\n /** Hex color for the new background. Default \"#FFFFFF\". Ignored if `bgUrl` is set. */\n bgColor?: string;\n /** Remote URL of an image to use as the new background. Takes precedence over `bgColor`. */\n bgUrl?: string;\n /** Output format. \"jpg\" is smallest. Default \"png\". */\n format?: OpaqueFormat;\n}\n\nexport interface BatchInput {\n /** Array of local paths / buffers / blobs. Up to 10. */\n files: Array<string | Buffer | Blob | ArrayBuffer | Uint8Array>;\n /** Optional filenames aligned to `files`. */\n filenames?: string[];\n /** Output format for each image. Default \"png\". */\n format?: OutputFormat;\n}\n\nexport interface BatchUrlInput {\n /** Remote URLs to process. Up to 10. */\n urls: string[];\n /** Output format for each image. Default \"png\". */\n format?: OutputFormat;\n}\n\nexport interface BatchResultItem {\n filename?: string;\n url?: string;\n success: boolean;\n format?: OutputFormat;\n size_bytes?: number;\n data_base64?: string;\n error?: string;\n}\n\nexport interface BatchResponse {\n count: number;\n format: OutputFormat;\n results: BatchResultItem[];\n}\n\nexport interface MaskInput {\n file: FileInput;\n filename?: string;\n format?: OutputFormat;\n}\n\nexport interface SmartCropInput {\n file: FileInput;\n filename?: string;\n /** Padding around the subject bbox, in pixels. Default 24. */\n padding?: number;\n /** Return transparent cutout (true) or cropped region from original (false). Default true. */\n transparent?: boolean;\n format?: OpaqueFormat;\n}\n\nexport interface ShadowInput {\n file: FileInput;\n filename?: string;\n bgColor?: string;\n bgUrl?: string;\n shadowColor?: string;\n shadowOffsetX?: number;\n shadowOffsetY?: number;\n shadowBlur?: number;\n shadowOpacity?: number;\n format?: OpaqueFormat;\n}\n\nexport interface StickerInput {\n file: FileInput;\n filename?: string;\n /** Hex color for the outline. Default \"#FFFFFF\". */\n strokeColor?: string;\n /** Outline width in pixels. Default 20. */\n strokeWidth?: number;\n format?: OutputFormat;\n}\n\nexport interface OutlineInput {\n file: FileInput;\n filename?: string;\n /** Hex color for the outline. Default \"#000000\". */\n outlineColor?: string;\n /** Outline width in pixels. Default 4. */\n outlineWidth?: number;\n format?: OutputFormat;\n}\n\nexport interface StudioShotInput {\n file: FileInput;\n filename?: string;\n bgColor?: string;\n /** e.g. \"1:1\", \"4:5\", \"16:9\". Default \"1:1\". */\n aspect?: string;\n padding?: number;\n shadow?: boolean;\n format?: OpaqueFormat;\n}\n\nexport interface CompareInput {\n file: FileInput;\n filename?: string;\n format?: OutputFormat;\n}\n\nexport interface HealthResponse {\n status: string;\n model: string;\n}\n\n/**\n * Error thrown when the API returns a non-2xx response.\n */\nexport class KnockoutError extends Error {\n public readonly status: number;\n public readonly code: \"auth\" | \"rate_limit\" | \"bad_request\" | \"payload_too_large\" | \"server\" | \"unknown\";\n public readonly body: string;\n\n constructor(status: number, body: string) {\n const code = KnockoutError.classify(status);\n super(`Knockout API error ${status} (${code}): ${body || \"no body\"}`);\n this.name = \"KnockoutError\";\n this.status = status;\n this.code = code;\n this.body = body;\n }\n\n private static classify(status: number): KnockoutError[\"code\"] {\n if (status === 401 || status === 403) return \"auth\";\n if (status === 429) return \"rate_limit\";\n if (status === 413) return \"payload_too_large\";\n if (status >= 400 && status < 500) return \"bad_request\";\n if (status >= 500) return \"server\";\n return \"unknown\";\n }\n}\n\n/**\n * useknockout API client.\n *\n * All methods return a `Buffer` (Node) of the processed image bytes.\n * Use `.toString(\"base64\")` or `writeFile(path, buf)` to persist.\n */\nexport class Knockout {\n private readonly baseUrl: string;\n private readonly token: string | undefined;\n private readonly timeoutMs: number;\n private readonly fetchImpl: typeof fetch;\n\n constructor(options: KnockoutOptions = {}) {\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.token = options.token;\n this.timeoutMs = options.timeoutMs ?? 60_000;\n const fetchRef = options.fetch ?? globalThis.fetch;\n if (!fetchRef) {\n throw new Error(\n \"Global fetch is unavailable. Provide `options.fetch` or use Node 18+.\"\n );\n }\n this.fetchImpl = fetchRef.bind(globalThis);\n }\n\n /** Hit GET /health — no auth required. */\n async health(): Promise<HealthResponse> {\n const res = await this.request(\"GET\", \"/health\");\n const body = await res.text();\n if (!res.ok) throw new KnockoutError(res.status, body);\n return JSON.parse(body) as HealthResponse;\n }\n\n /**\n * Remove the background from an image, returning the cleaned PNG/WebP bytes.\n *\n * @example\n * const png = await client.remove({ file: \"./input.jpg\" });\n */\n async remove(input: RemoveInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob(input);\n\n const form = new FormData();\n form.append(\"file\", blob, filename);\n\n const res = await this.request(\"POST\", `/remove?format=${format}`, {\n body: form,\n });\n\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Remove the background from a remote URL, returning the cleaned PNG/WebP bytes.\n *\n * @example\n * const png = await client.removeUrl({ url: \"https://example.com/cat.jpg\" });\n */\n async removeUrl(input: RemoveUrlInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const res = await this.request(\"POST\", \"/remove-url\", {\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ url: input.url, format }),\n });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Replace the background with a solid color or a remote image.\n *\n * @example Solid color\n * const jpg = await client.replaceBackground({ file: \"./cat.jpg\", bgColor: \"#FF5733\", format: \"jpg\" });\n *\n * @example Remote image as new background\n * const png = await client.replaceBackground({\n * file: \"./cat.jpg\",\n * bgUrl: \"https://example.com/beach.jpg\",\n * });\n */\n async replaceBackground(input: ReplaceBgInput): Promise<Buffer> {\n const format: OpaqueFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n\n const form = new FormData();\n form.append(\"file\", blob, filename);\n\n const params = new URLSearchParams({ format });\n if (input.bgUrl) params.set(\"bg_url\", input.bgUrl);\n if (input.bgColor) params.set(\"bg_color\", input.bgColor);\n\n const res = await this.request(\"POST\", `/replace-bg?${params.toString()}`, {\n body: form,\n });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Remove the background from up to 10 images in a single call.\n * Returns a JSON object with base64-encoded result bytes per image.\n *\n * @example\n * const batch = await client.removeBatch({\n * files: [\"./a.jpg\", \"./b.jpg\", \"./c.jpg\"],\n * format: \"png\",\n * });\n * for (const r of batch.results) {\n * if (r.success) await writeFile(r.filename!, Buffer.from(r.data_base64!, \"base64\"));\n * }\n */\n async removeBatch(input: BatchInput): Promise<BatchResponse> {\n const format: OutputFormat = input.format ?? \"png\";\n if (input.files.length === 0) throw new Error(\"At least one file required\");\n if (input.files.length > 10) throw new Error(\"Max 10 files per batch\");\n\n const form = new FormData();\n for (let i = 0; i < input.files.length; i++) {\n const name = input.filenames?.[i];\n const { blob, filename } = await toBlob({ file: input.files[i]!, filename: name });\n form.append(\"files\", blob, filename);\n }\n\n const res = await this.request(\"POST\", `/remove-batch?format=${format}`, {\n body: form,\n });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return (await res.json()) as BatchResponse;\n }\n\n /**\n * Return only the alpha mask as a grayscale PNG/WebP.\n * Useful when chaining into your own compositing pipeline.\n */\n async mask(input: MaskInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/mask\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Auto-crop to the subject's tight bounding box with configurable padding.\n * Returns either a transparent cutout or a cropped region from the original image.\n */\n async smartCrop(input: SmartCropInput): Promise<Buffer> {\n const transparent = input.transparent ?? true;\n const format: OpaqueFormat =\n (input.format as OpaqueFormat | undefined) ?? (transparent ? \"png\" : \"jpg\");\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n form.append(\"padding\", String(input.padding ?? 24));\n form.append(\"transparent\", transparent ? \"true\" : \"false\");\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/smart-crop\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Composite subject onto a new background with a configurable drop shadow.\n */\n async shadow(input: ShadowInput): Promise<Buffer> {\n const format: OpaqueFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n if (input.bgColor) form.append(\"bg_color\", input.bgColor);\n if (input.bgUrl) form.append(\"bg_url\", input.bgUrl);\n if (input.shadowColor) form.append(\"shadow_color\", input.shadowColor);\n if (input.shadowOffsetX !== undefined) form.append(\"shadow_offset_x\", String(input.shadowOffsetX));\n if (input.shadowOffsetY !== undefined) form.append(\"shadow_offset_y\", String(input.shadowOffsetY));\n if (input.shadowBlur !== undefined) form.append(\"shadow_blur\", String(input.shadowBlur));\n if (input.shadowOpacity !== undefined) form.append(\"shadow_opacity\", String(input.shadowOpacity));\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/shadow\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Sticker style — subject with a thick outline on transparent background.\n * Perfect for WhatsApp / iMessage / Telegram stickers.\n */\n async sticker(input: StickerInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n if (input.strokeColor) form.append(\"stroke_color\", input.strokeColor);\n if (input.strokeWidth !== undefined) form.append(\"stroke_width\", String(input.strokeWidth));\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/sticker\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Subject on transparent background with a thin configurable outline.\n */\n async outline(input: OutlineInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n if (input.outlineColor) form.append(\"outline_color\", input.outlineColor);\n if (input.outlineWidth !== undefined) form.append(\"outline_width\", String(input.outlineWidth));\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/outline\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * E-commerce preset — cutout + tight crop + centered + optional shadow on a standard aspect canvas.\n */\n async studioShot(input: StudioShotInput): Promise<Buffer> {\n const format: OpaqueFormat = input.format ?? \"jpg\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n if (input.bgColor) form.append(\"bg_color\", input.bgColor);\n if (input.aspect) form.append(\"aspect\", input.aspect);\n if (input.padding !== undefined) form.append(\"padding\", String(input.padding));\n if (input.shadow !== undefined) form.append(\"shadow\", input.shadow ? \"true\" : \"false\");\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/studio-shot\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Before/after side-by-side preview — original on left, transparent cutout (on a checkerboard) on right.\n */\n async compare(input: CompareInput): Promise<Buffer> {\n const format: OutputFormat = input.format ?? \"png\";\n const { blob, filename } = await toBlob({ file: input.file, filename: input.filename });\n const form = new FormData();\n form.append(\"file\", blob, filename);\n form.append(\"format\", format);\n const res = await this.request(\"POST\", \"/compare\", { body: form });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return Buffer.from(await res.arrayBuffer());\n }\n\n /**\n * Remove the background from up to 10 remote image URLs in a single call.\n *\n * @example\n * const batch = await client.removeBatchUrl({\n * urls: [\"https://a.jpg\", \"https://b.jpg\"],\n * });\n */\n async removeBatchUrl(input: BatchUrlInput): Promise<BatchResponse> {\n const format: OutputFormat = input.format ?? \"png\";\n if (input.urls.length === 0) throw new Error(\"At least one URL required\");\n if (input.urls.length > 10) throw new Error(\"Max 10 URLs per batch\");\n\n const res = await this.request(\"POST\", \"/remove-batch-url\", {\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ urls: input.urls, format }),\n });\n if (!res.ok) throw new KnockoutError(res.status, await res.text());\n return (await res.json()) as BatchResponse;\n }\n\n private async request(\n method: \"GET\" | \"POST\",\n path: string,\n init: { headers?: Record<string, string>; body?: BodyInit } = {}\n ): Promise<Response> {\n const url = `${this.baseUrl}${path}`;\n const headers: Record<string, string> = {\n \"User-Agent\": `useknockout-node/${SDK_VERSION}`,\n ...(init.headers ?? {}),\n };\n if (this.token) headers[\"Authorization\"] = `Bearer ${this.token}`;\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n try {\n return await this.fetchImpl(url, {\n method,\n headers,\n body: init.body,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n }\n}\n\nasync function toBlob(\n input: { file: string | Buffer | Blob | ArrayBuffer | Uint8Array; filename?: string }\n): Promise<{ blob: Blob; filename: string }> {\n const { file } = input;\n const filename = input.filename ?? inferFilename(file);\n\n if (typeof file === \"string\") {\n const data = await readFile(file);\n return { blob: new Blob([new Uint8Array(data)]), filename };\n }\n if (file instanceof Blob) {\n return { blob: file, filename };\n }\n if (file instanceof ArrayBuffer) {\n return { blob: new Blob([new Uint8Array(file)]), filename };\n }\n if (file instanceof Uint8Array) {\n return { blob: new Blob([new Uint8Array(file)]), filename };\n }\n if (Buffer.isBuffer(file)) {\n return {\n blob: new Blob([new Uint8Array(file)]),\n filename,\n };\n }\n throw new TypeError(\"Unsupported `file` input. Provide a path, Buffer, Blob, ArrayBuffer, or Uint8Array.\");\n}\n\nfunction inferFilename(file: string | Buffer | Blob | ArrayBuffer | Uint8Array): string {\n if (typeof file === \"string\") return basename(file) || \"image\";\n return \"image\";\n}\n\nexport default Knockout;\n"]}
|