@immagin/client 0.2.0 → 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 +46 -26
- package/dist/index.d.mts +3 -7
- package/dist/index.mjs +48 -7
- package/package.json +7 -8
package/README.md
CHANGED
|
@@ -17,19 +17,20 @@ import { Immagin } from '@immagin/client'
|
|
|
17
17
|
|
|
18
18
|
const client = new Immagin({ apiKey: 'imk_...' })
|
|
19
19
|
|
|
20
|
-
// Get a processed image URL
|
|
20
|
+
// Get a processed image URL (via API)
|
|
21
21
|
const url = await client.images.url('photos/hero.jpg', {
|
|
22
22
|
size: [800, 600],
|
|
23
23
|
})
|
|
24
24
|
|
|
25
25
|
// Upload an image
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
import { readFileSync } from 'node:fs'
|
|
27
|
+
const buffer = readFileSync('photo.jpg')
|
|
28
|
+
await client.images.upload(buffer, 'photos/hero.jpg')
|
|
28
29
|
```
|
|
29
30
|
|
|
30
31
|
## Images
|
|
31
32
|
|
|
32
|
-
### Get a processed URL
|
|
33
|
+
### Get a processed URL (via API)
|
|
33
34
|
|
|
34
35
|
Returns a signed URL that serves the image through Immagin's processing pipeline.
|
|
35
36
|
|
|
@@ -41,8 +42,7 @@ With transformations:
|
|
|
41
42
|
|
|
42
43
|
```ts
|
|
43
44
|
const url = await client.images.url('photo.jpg', {
|
|
44
|
-
size: [400],
|
|
45
|
-
size: [400, 300], // width and height
|
|
45
|
+
size: [400, 300],
|
|
46
46
|
text: {
|
|
47
47
|
text: 'Hello',
|
|
48
48
|
position: 'bottom-right', // top-left, top-right, bottom-left, bottom-right, center
|
|
@@ -53,36 +53,54 @@ const url = await client.images.url('photo.jpg', {
|
|
|
53
53
|
})
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
###
|
|
56
|
+
### Sign URLs locally (without API call)
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
Generate signed image URLs on the server without making an API request. Requires `tenantId` and `tenantSecret` in the constructor.
|
|
59
59
|
|
|
60
60
|
```ts
|
|
61
|
-
const
|
|
61
|
+
const client = new Immagin({
|
|
62
|
+
apiKey: 'imk_...',
|
|
63
|
+
tenantId: 'your-tenant-id',
|
|
64
|
+
tenantSecret: 'your-tenant-secret',
|
|
65
|
+
})
|
|
62
66
|
|
|
63
|
-
//
|
|
64
|
-
|
|
67
|
+
// Synchronous - no network request
|
|
68
|
+
const url = client.images.signedUrl('photo.jpg')
|
|
69
|
+
|
|
70
|
+
// With transformations
|
|
71
|
+
const thumb = client.images.signedUrl('photo.jpg', {
|
|
72
|
+
size: [800, 600],
|
|
73
|
+
text: { text: '© My Company', position: 'bottom-right', opacity: 0.5 },
|
|
74
|
+
})
|
|
65
75
|
```
|
|
66
76
|
|
|
67
|
-
|
|
77
|
+
> **Note:** This uses `node:crypto` and is intended for server-side use only. Never expose your tenant secret in client-side code.
|
|
68
78
|
|
|
69
|
-
|
|
79
|
+
### Get a pre-signed upload URL
|
|
80
|
+
|
|
81
|
+
Returns a pre-signed S3 URL for direct upload (expires in 5 minutes). Useful for browser uploads where you don't want to expose your API key.
|
|
70
82
|
|
|
71
83
|
```ts
|
|
72
|
-
//
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
84
|
+
// Server: get the presigned URL
|
|
85
|
+
const { uploadUrl, key } = await client.images.signUrl('photos/hero.jpg')
|
|
86
|
+
// Return uploadUrl to the browser
|
|
87
|
+
|
|
88
|
+
// Browser: upload directly to S3
|
|
89
|
+
await fetch(uploadUrl, {
|
|
90
|
+
method: 'PUT',
|
|
91
|
+
body: file,
|
|
77
92
|
})
|
|
93
|
+
```
|
|
78
94
|
|
|
79
|
-
|
|
95
|
+
### Upload (Node.js)
|
|
96
|
+
|
|
97
|
+
Convenience method that gets a signed URL and uploads in one call. The file goes directly to S3 and never passes through the API.
|
|
98
|
+
|
|
99
|
+
```ts
|
|
80
100
|
import { readFileSync } from 'node:fs'
|
|
101
|
+
|
|
81
102
|
const buffer = readFileSync('photo.jpg')
|
|
82
|
-
await client.images.upload(buffer,
|
|
83
|
-
key: 'uploads/photo.jpg',
|
|
84
|
-
contentType: 'image/jpeg',
|
|
85
|
-
})
|
|
103
|
+
await client.images.upload(buffer, 'uploads/photo.jpg')
|
|
86
104
|
```
|
|
87
105
|
|
|
88
106
|
### List
|
|
@@ -107,7 +125,7 @@ await client.images.delete('uploads/photo.jpg')
|
|
|
107
125
|
|
|
108
126
|
## API Keys
|
|
109
127
|
|
|
110
|
-
Manage API keys programmatically.
|
|
128
|
+
Manage API keys programmatically.
|
|
111
129
|
|
|
112
130
|
### Create
|
|
113
131
|
|
|
@@ -151,8 +169,10 @@ try {
|
|
|
151
169
|
|
|
152
170
|
```ts
|
|
153
171
|
const client = new Immagin({
|
|
154
|
-
apiKey: 'imk_...',
|
|
155
|
-
baseUrl: 'https://...',
|
|
172
|
+
apiKey: 'imk_...', // Required
|
|
173
|
+
baseUrl: 'https://...', // Optional, defaults to https://gateway.immag.in
|
|
174
|
+
tenantId: 'your-tenant-id', // Optional, required for signedUrl()
|
|
175
|
+
tenantSecret: 'your-secret', // Optional, required for signedUrl()
|
|
156
176
|
})
|
|
157
177
|
```
|
|
158
178
|
|
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
|
|
64
|
-
upload(file: Blob | Buffer | ReadableStream,
|
|
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
|
|
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
|
|
32
|
-
|
|
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
|
|
35
|
-
} });
|
|
72
|
+
contentType
|
|
73
|
+
} : { key } });
|
|
36
74
|
}
|
|
37
|
-
async upload(file,
|
|
38
|
-
const
|
|
39
|
-
const signResult = await this.
|
|
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.
|
|
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
|
+
}
|