@immagin/client 0.1.0 → 0.2.1

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
@@ -17,19 +17,23 @@ 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
- const file = new Blob([buffer], { type: 'image/jpeg' })
27
- await client.images.upload(file, { key: 'photos/hero.jpg' })
26
+ import { readFileSync } from 'node:fs'
27
+ const buffer = readFileSync('photo.jpg')
28
+ await client.images.upload(buffer, {
29
+ key: 'photos/hero.jpg',
30
+ contentType: 'image/jpeg',
31
+ })
28
32
  ```
29
33
 
30
34
  ## Images
31
35
 
32
- ### Get a processed URL
36
+ ### Get a processed URL (via API)
33
37
 
34
38
  Returns a signed URL that serves the image through Immagin's processing pipeline.
35
39
 
@@ -41,8 +45,7 @@ With transformations:
41
45
 
42
46
  ```ts
43
47
  const url = await client.images.url('photo.jpg', {
44
- size: [400], // width only
45
- size: [400, 300], // width and height
48
+ size: [400, 300],
46
49
  text: {
47
50
  text: 'Hello',
48
51
  position: 'bottom-right', // top-left, top-right, bottom-left, bottom-right, center
@@ -53,31 +56,53 @@ const url = await client.images.url('photo.jpg', {
53
56
  })
54
57
  ```
55
58
 
59
+ ### Sign URLs locally (without API call)
60
+
61
+ Generate signed image URLs on the server without making an API request. Requires `tenantId` and `tenantSecret` in the constructor.
62
+
63
+ ```ts
64
+ const client = new Immagin({
65
+ apiKey: 'imk_...',
66
+ tenantId: 'your-tenant-id',
67
+ tenantSecret: 'your-tenant-secret',
68
+ })
69
+
70
+ // Synchronous - no network request
71
+ const url = client.images.signedUrl('photo.jpg')
72
+
73
+ // With transformations
74
+ const thumb = client.images.signedUrl('photo.jpg', {
75
+ size: [800, 600],
76
+ text: { text: '© My Company', position: 'bottom-right', opacity: 0.5 },
77
+ })
78
+ ```
79
+
80
+ > **Note:** This uses `node:crypto` and is intended for server-side use only. Never expose your tenant secret in client-side code.
81
+
56
82
  ### Get a pre-signed upload URL
57
83
 
58
- Returns a pre-signed S3 URL for direct upload. Useful when you need to handle the upload yourself (e.g. from a mobile app or with a custom upload flow).
84
+ 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.
59
85
 
60
86
  ```ts
87
+ // Server: get the presigned URL
61
88
  const { uploadUrl, key } = await client.images.signUrl('photos/hero.jpg', 'image/jpeg')
89
+ // Return uploadUrl to the browser
62
90
 
63
- // Upload directly to S3 yourself
64
- await fetch(uploadUrl, { method: 'PUT', body: file })
91
+ // Browser: upload directly to S3
92
+ await fetch(uploadUrl, {
93
+ method: 'PUT',
94
+ body: file,
95
+ headers: { 'content-type': 'image/jpeg' },
96
+ })
65
97
  ```
66
98
 
67
- ### Upload
99
+ ### Upload (Node.js)
68
100
 
69
101
  Convenience method that gets a signed URL and uploads in one call. The file goes directly to S3 and never passes through the API.
70
102
 
71
103
  ```ts
72
- // Browser
73
- const input = document.querySelector('input[type="file"]')
74
- await client.images.upload(input.files[0], {
75
- key: 'uploads/photo.jpg',
76
- contentType: 'image/jpeg',
77
- })
78
-
79
- // Node.js
80
104
  import { readFileSync } from 'node:fs'
105
+
81
106
  const buffer = readFileSync('photo.jpg')
82
107
  await client.images.upload(buffer, {
83
108
  key: 'uploads/photo.jpg',
@@ -107,7 +132,7 @@ await client.images.delete('uploads/photo.jpg')
107
132
 
108
133
  ## API Keys
109
134
 
110
- Manage API keys programmatically. Useful for building admin tools or rotating keys.
135
+ Manage API keys programmatically.
111
136
 
112
137
  ### Create
113
138
 
@@ -151,8 +176,10 @@ try {
151
176
 
152
177
  ```ts
153
178
  const client = new Immagin({
154
- apiKey: 'imk_...', // Required
155
- baseUrl: 'https://...', // Optional, defaults to https://gateway.immag.in
179
+ apiKey: 'imk_...', // Required
180
+ baseUrl: 'https://...', // Optional, defaults to https://gateway.immag.in
181
+ tenantId: 'your-tenant-id', // Optional, required for signedUrl()
182
+ tenantSecret: 'your-secret', // Optional, required for signedUrl()
156
183
  })
157
184
  ```
158
185
 
package/dist/index.d.mts CHANGED
@@ -50,12 +50,15 @@ interface CreateKeyResult {
50
50
  interface ImmaginConfig {
51
51
  apiKey: string;
52
52
  baseUrl?: string;
53
+ tenantId?: string;
54
+ tenantSecret?: string;
53
55
  }
54
56
  //#endregion
55
57
  //#region src/resources/images.d.ts
56
58
  declare class ImagesResource {
57
59
  private client;
58
60
  constructor(client: Immagin);
61
+ signedUrl(key: string, edits?: ImageEdits): string;
59
62
  url(key: string, options?: ImageUrlOptions): Promise<string>;
60
63
  signUrl(key: string, contentType?: string): Promise<UploadResult>;
61
64
  upload(file: Blob | Buffer | ReadableStream, options: UploadOptions): Promise<UploadResult>;
@@ -78,6 +81,10 @@ declare class KeysResource {
78
81
  declare class Immagin {
79
82
  private apiKey;
80
83
  private baseUrl;
84
+ /** @internal */
85
+ tenantId?: string;
86
+ /** @internal */
87
+ tenantSecret?: string;
81
88
  images: ImagesResource;
82
89
  keys: KeysResource;
83
90
  constructor(config: ImmaginConfig);
package/dist/index.mjs CHANGED
@@ -1,8 +1,18 @@
1
+ import { createHmac } from "node:crypto";
2
+
1
3
  //#region src/resources/images.ts
2
4
  var ImagesResource = class {
3
5
  constructor(client) {
4
6
  this.client = client;
5
7
  }
8
+ signedUrl(key, edits) {
9
+ const { tenantId, tenantSecret } = this.client;
10
+ if (!tenantId || !tenantSecret) throw new Error("tenantId and tenantSecret are required for signedUrl(). Pass them in the Immagin constructor.");
11
+ const payload = { key };
12
+ if (edits && Object.keys(edits).length > 0) payload.edits = edits;
13
+ const base64 = Buffer.from(JSON.stringify(payload)).toString("base64");
14
+ return `https://${tenantId}.immag.in/${base64}?sig=${createHmac("sha256", tenantSecret).update(base64).digest("hex").slice(0, 16)}`;
15
+ }
6
16
  async url(key, options) {
7
17
  const params = { key };
8
18
  if (options?.size) {
@@ -80,11 +90,17 @@ const DEFAULT_BASE_URL = "https://gateway.immag.in";
80
90
  var Immagin = class {
81
91
  apiKey;
82
92
  baseUrl;
93
+ /** @internal */
94
+ tenantId;
95
+ /** @internal */
96
+ tenantSecret;
83
97
  images;
84
98
  keys;
85
99
  constructor(config) {
86
100
  this.apiKey = config.apiKey;
87
101
  this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
102
+ this.tenantId = config.tenantId;
103
+ this.tenantSecret = config.tenantSecret;
88
104
  this.images = new ImagesResource(this);
89
105
  this.keys = new KeysResource(this);
90
106
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@immagin/client",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "Node.js and browser client for the Immagin image processing API",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -34,14 +34,15 @@
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
+ },
37
43
  "devDependencies": {
38
44
  "tsdown": "^0.20.3",
39
45
  "typescript": "^5.7.2",
40
46
  "vitest": "^3.0.5"
41
- },
42
- "scripts": {
43
- "build": "tsdown",
44
- "dev": "tsdown --watch",
45
- "test": "vitest run"
46
47
  }
47
- }
48
+ }