@immagin/client 0.2.1 → 0.2.2

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 CHANGED
@@ -25,10 +25,7 @@ const url = await client.images.url('photos/hero.jpg', {
25
25
  // Upload an image
26
26
  import { readFileSync } from 'node:fs'
27
27
  const buffer = readFileSync('photo.jpg')
28
- await client.images.upload(buffer, {
29
- key: 'photos/hero.jpg',
30
- contentType: 'image/jpeg',
31
- })
28
+ await client.images.upload(buffer, 'photos/hero.jpg')
32
29
  ```
33
30
 
34
31
  ## Images
@@ -85,14 +82,13 @@ Returns a pre-signed S3 URL for direct upload (expires in 5 minutes). Useful for
85
82
 
86
83
  ```ts
87
84
  // Server: get the presigned URL
88
- const { uploadUrl, key } = await client.images.signUrl('photos/hero.jpg', 'image/jpeg')
85
+ const { uploadUrl, key } = await client.images.signUrl('photos/hero.jpg')
89
86
  // Return uploadUrl to the browser
90
87
 
91
88
  // Browser: upload directly to S3
92
89
  await fetch(uploadUrl, {
93
90
  method: 'PUT',
94
91
  body: file,
95
- headers: { 'content-type': 'image/jpeg' },
96
92
  })
97
93
  ```
98
94
 
@@ -104,10 +100,7 @@ Convenience method that gets a signed URL and uploads in one call. The file goes
104
100
  import { readFileSync } from 'node:fs'
105
101
 
106
102
  const buffer = readFileSync('photo.jpg')
107
- await client.images.upload(buffer, {
108
- key: 'uploads/photo.jpg',
109
- contentType: 'image/jpeg',
110
- })
103
+ await client.images.upload(buffer, 'uploads/photo.jpg')
111
104
  ```
112
105
 
113
106
  ### List
package/dist/index.d.mts CHANGED
@@ -13,10 +13,6 @@ interface ImageEdits {
13
13
  text?: TextOverlay;
14
14
  }
15
15
  interface ImageUrlOptions extends ImageEdits {}
16
- interface UploadOptions {
17
- key: string;
18
- contentType?: string;
19
- }
20
16
  interface UploadResult {
21
17
  uploadUrl: string;
22
18
  key: string;
@@ -60,8 +56,8 @@ declare class ImagesResource {
60
56
  constructor(client: Immagin);
61
57
  signedUrl(key: string, edits?: ImageEdits): string;
62
58
  url(key: string, options?: ImageUrlOptions): Promise<string>;
63
- signUrl(key: string, contentType?: string): Promise<UploadResult>;
64
- upload(file: Blob | Buffer | ReadableStream, options: UploadOptions): Promise<UploadResult>;
59
+ signUrl(key: string): Promise<UploadResult>;
60
+ upload(file: Blob | Buffer | ReadableStream, key: string): Promise<UploadResult>;
65
61
  list(options?: ListImagesOptions): Promise<ListImagesResult>;
66
62
  delete(key: string): Promise<void>;
67
63
  }
@@ -102,4 +98,4 @@ declare class ImmaginError extends Error {
102
98
  constructor(message: string, status: number, body?: unknown | undefined);
103
99
  }
104
100
  //#endregion
105
- export { type ApiKey, type CreateKeyResult, type ImageEdits, type ImageEntry, type ImageUrlOptions, Immagin, type ImmaginConfig, ImmaginError, type ListImagesOptions, type ListImagesResult, type TextOverlay, type TextPosition, type UploadOptions, type UploadResult };
101
+ export { type ApiKey, type CreateKeyResult, type ImageEdits, type ImageEntry, type ImageUrlOptions, Immagin, type ImmaginConfig, ImmaginError, type ListImagesOptions, type ListImagesResult, type TextOverlay, type TextPosition, type UploadResult };
package/dist/index.mjs CHANGED
@@ -1,6 +1,43 @@
1
1
  import { createHmac } from "node:crypto";
2
2
 
3
3
  //#region src/resources/images.ts
4
+ const MIME_TYPES = {
5
+ jpg: "image/jpeg",
6
+ jpeg: "image/jpeg",
7
+ png: "image/png",
8
+ gif: "image/gif",
9
+ webp: "image/webp",
10
+ avif: "image/avif",
11
+ svg: "image/svg+xml",
12
+ tiff: "image/tiff",
13
+ tif: "image/tiff",
14
+ bmp: "image/bmp",
15
+ ico: "image/x-icon",
16
+ heic: "image/heic",
17
+ heif: "image/heif"
18
+ };
19
+ function mimeFromKey(key) {
20
+ const ext = key.split(".").pop()?.toLowerCase();
21
+ return ext ? MIME_TYPES[ext] : void 0;
22
+ }
23
+ function mimeFromBuffer(buf) {
24
+ if (buf.length < 12) return void 0;
25
+ if (buf[0] === 255 && buf[1] === 216 && buf[2] === 255) return "image/jpeg";
26
+ if (buf[0] === 137 && buf[1] === 80 && buf[2] === 78 && buf[3] === 71) return "image/png";
27
+ if (buf[0] === 71 && buf[1] === 73 && buf[2] === 70) return "image/gif";
28
+ if (buf[0] === 82 && buf[1] === 73 && buf[2] === 70 && buf[3] === 70 && buf[8] === 87 && buf[9] === 69 && buf[10] === 66 && buf[11] === 80) return "image/webp";
29
+ if (buf[0] === 66 && buf[1] === 77) return "image/bmp";
30
+ if (buf[4] === 102 && buf[5] === 116 && buf[6] === 121 && buf[7] === 112) {
31
+ const brand = buf.slice(8, 12).toString("ascii");
32
+ if (brand === "avif" || brand === "avis") return "image/avif";
33
+ if (brand === "heic" || brand === "heix") return "image/heic";
34
+ if (brand === "heif" || brand === "mif1") return "image/heif";
35
+ }
36
+ }
37
+ function mimeFromFile(file) {
38
+ if (typeof Blob !== "undefined" && file instanceof Blob && file.type) return file.type;
39
+ if (typeof Buffer !== "undefined" && Buffer.isBuffer(file)) return mimeFromBuffer(file);
40
+ }
4
41
  var ImagesResource = class {
5
42
  constructor(client) {
6
43
  this.client = client;
@@ -28,15 +65,19 @@ var ImagesResource = class {
28
65
  }
29
66
  return (await this.client.request("GET", "/v1/images/url", { params })).url;
30
67
  }
31
- async signUrl(key, contentType) {
32
- return this.client.request("POST", "/v1/images/sign-url", { body: {
68
+ async signUrl(key) {
69
+ const contentType = mimeFromKey(key);
70
+ return this.client.request("POST", "/v1/images/sign-url", { body: contentType ? {
33
71
  key,
34
- contentType: contentType || "application/octet-stream"
35
- } });
72
+ contentType
73
+ } : { key } });
36
74
  }
37
- async upload(file, options) {
38
- const { key, contentType } = options;
39
- const signResult = await this.signUrl(key, contentType);
75
+ async upload(file, key) {
76
+ const contentType = mimeFromFile(file) ?? mimeFromKey(key);
77
+ const signResult = await this.client.request("POST", "/v1/images/sign-url", { body: contentType ? {
78
+ key,
79
+ contentType
80
+ } : { key } });
40
81
  await fetch(signResult.uploadUrl, {
41
82
  method: "PUT",
42
83
  body: file,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@immagin/client",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Node.js and browser client for the Immagin image processing API",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -34,15 +34,14 @@
34
34
  "publishConfig": {
35
35
  "access": "public"
36
36
  },
37
- "scripts": {
38
- "build": "tsdown",
39
- "dev": "tsdown --watch",
40
- "test": "vitest run",
41
- "prepublishOnly": "tsdown"
42
- },
43
37
  "devDependencies": {
44
38
  "tsdown": "^0.20.3",
45
39
  "typescript": "^5.7.2",
46
40
  "vitest": "^3.0.5"
41
+ },
42
+ "scripts": {
43
+ "build": "tsdown",
44
+ "dev": "tsdown --watch",
45
+ "test": "vitest run"
47
46
  }
48
- }
47
+ }