cloud-service-kit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +200 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +5 -0
- package/dist/lib/s3.client.d.ts +4 -0
- package/dist/lib/s3.client.js +24 -0
- package/dist/modules/media/index.d.ts +2 -0
- package/dist/modules/media/index.js +5 -0
- package/dist/modules/media/media.module.d.ts +19 -0
- package/dist/modules/media/media.module.js +91 -0
- package/dist/modules/media/media.types.d.ts +20 -0
- package/dist/modules/media/media.types.js +2 -0
- package/dist/s3-media-client.d.ts +7 -0
- package/dist/s3-media-client.js +12 -0
- package/dist/types.d.ts +9 -0
- package/dist/types.js +2 -0
- package/package.json +37 -0
package/README.md
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# cloud-service-kit
|
|
2
|
+
|
|
3
|
+
A modular cloud service toolkit for Node.js. Handles S3 media uploads, with support for more services (email, etc.) coming soon.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install cloud-service-kit
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Prerequisites
|
|
12
|
+
|
|
13
|
+
- Node.js >= 18.0.0
|
|
14
|
+
- AWS S3 bucket with access credentials
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { S3MediaClient } from "cloud-service-kit";
|
|
20
|
+
|
|
21
|
+
const s3 = new S3MediaClient({
|
|
22
|
+
aws: {
|
|
23
|
+
region: "us-east-1",
|
|
24
|
+
bucket: "your-bucket-name",
|
|
25
|
+
accessKey: "YOUR_AWS_ACCESS_KEY",
|
|
26
|
+
secretKey: "YOUR_AWS_SECRET_KEY",
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Upload image from a live URL
|
|
31
|
+
const result = await s3.media.uploadFromUrl("https://example.com/photo.jpg", {
|
|
32
|
+
folder: "uploads",
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Upload from buffer (e.g. Express + multer)
|
|
36
|
+
const result2 = await s3.media.uploadBuffer(fileBuffer, {
|
|
37
|
+
contentType: "image/jpeg",
|
|
38
|
+
folder: "user-uploads",
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
console.log(result.url); // Full S3 URL
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Setup
|
|
45
|
+
|
|
46
|
+
### Using environment variables (recommended)
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { S3MediaClient } from "cloud-service-kit";
|
|
50
|
+
|
|
51
|
+
const s3 = new S3MediaClient({
|
|
52
|
+
aws: {
|
|
53
|
+
region: process.env.AWS_REGION!,
|
|
54
|
+
bucket: process.env.AWS_BUCKET!,
|
|
55
|
+
accessKey: process.env.AWS_ACCESS_KEY!,
|
|
56
|
+
secretKey: process.env.AWS_SECRET_KEY!,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
> Initialize once at app startup and reuse the instance throughout your application.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Modules
|
|
66
|
+
|
|
67
|
+
### Media Module
|
|
68
|
+
|
|
69
|
+
Handles fetching images from URLs or accepting buffers and uploading them to AWS S3.
|
|
70
|
+
|
|
71
|
+
#### `s3.media.uploadFromUrl(url, options?)`
|
|
72
|
+
|
|
73
|
+
Fetches an image from a live URL and uploads it to S3.
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
const result = await s3.media.uploadFromUrl("https://example.com/photo.jpg");
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
With options:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
const result = await s3.media.uploadFromUrl("https://example.com/photo.jpg", {
|
|
83
|
+
folder: "uploads", // S3 folder prefix
|
|
84
|
+
key: "custom/path/photo.jpg", // or provide a full custom key
|
|
85
|
+
contentType: "image/jpeg", // override auto-detected content type
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Parameters:**
|
|
90
|
+
|
|
91
|
+
| Parameter | Type | Required | Description |
|
|
92
|
+
| --------------------- | -------- | -------- | ------------------------------------------------------------ |
|
|
93
|
+
| `url` | `string` | Yes | The live URL to fetch the image from |
|
|
94
|
+
| `options.key` | `string` | No | Custom S3 key. If omitted, a UUID-based key is auto-generated |
|
|
95
|
+
| `options.folder` | `string` | No | S3 folder prefix (e.g. `"uploads"`). Ignored if `key` is set |
|
|
96
|
+
| `options.contentType` | `string` | No | MIME type override. Auto-detected from response headers |
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
#### `s3.media.uploadBuffer(buffer, options?)`
|
|
101
|
+
|
|
102
|
+
Uploads a Buffer directly to S3. Useful for file uploads via multer/express.
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
// Example with Express + multer
|
|
106
|
+
app.post("/upload", upload.single("image"), async (req, res) => {
|
|
107
|
+
const result = await s3.media.uploadBuffer(req.file.buffer, {
|
|
108
|
+
contentType: req.file.mimetype,
|
|
109
|
+
folder: "user-uploads",
|
|
110
|
+
});
|
|
111
|
+
res.json(result);
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Parameters:**
|
|
116
|
+
|
|
117
|
+
| Parameter | Type | Required | Description |
|
|
118
|
+
| --------------------- | -------- | -------- | ------------------------------------------------------------ |
|
|
119
|
+
| `buffer` | `Buffer` | Yes | The file buffer to upload |
|
|
120
|
+
| `options.key` | `string` | No | Custom S3 key. If omitted, a UUID-based key is auto-generated |
|
|
121
|
+
| `options.folder` | `string` | No | S3 folder prefix. Ignored if `key` is set |
|
|
122
|
+
| `options.contentType` | `string` | No | MIME type. Defaults to `"application/octet-stream"` |
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
#### Response Format
|
|
127
|
+
|
|
128
|
+
Both methods return a `MediaUploadResponse`:
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
{
|
|
132
|
+
key: "uploads/550e8400-e29b-41d4-a716-446655440000.jpg",
|
|
133
|
+
url: "https://your-bucket.s3.us-east-1.amazonaws.com/uploads/550e8400-e29b-41d4-a716-446655440000.jpg",
|
|
134
|
+
bucket: "your-bucket-name",
|
|
135
|
+
contentType: "image/jpeg",
|
|
136
|
+
size: 102400
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
| Field | Type | Description |
|
|
141
|
+
| ------------- | -------- | ------------------------------------ |
|
|
142
|
+
| `key` | `string` | The S3 object key |
|
|
143
|
+
| `url` | `string` | Full public S3 URL |
|
|
144
|
+
| `bucket` | `string` | S3 bucket name |
|
|
145
|
+
| `contentType` | `string` | MIME content type of the file |
|
|
146
|
+
| `size` | `number` | File size in bytes |
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Exports
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import {
|
|
154
|
+
S3MediaClient, // Main S3 client class
|
|
155
|
+
S3MediaConfig, // Configuration interface
|
|
156
|
+
AWSConfig, // AWS credentials interface
|
|
157
|
+
MediaUploadOptions, // Upload options
|
|
158
|
+
MediaUploadResponse, // Upload response
|
|
159
|
+
} from "cloud-service-kit";
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## How It Works
|
|
163
|
+
|
|
164
|
+
1. **Initialization** — `new S3MediaClient(config)` creates an internal S3 client using your AWS credentials.
|
|
165
|
+
2. **Upload from URL** — `uploadFromUrl` uses native `fetch()` to download the image, auto-detects content type from response headers, generates a UUID-based S3 key (or uses your custom key), and uploads the buffer to S3.
|
|
166
|
+
3. **Upload from Buffer** — `uploadBuffer` takes a raw Buffer (e.g. from multer) and uploads it directly to S3.
|
|
167
|
+
4. **Key generation** — When no custom key is provided, a UUID is generated using `crypto.randomUUID()` and the file extension is resolved from the source URL or content type.
|
|
168
|
+
|
|
169
|
+
## Upcoming Modules
|
|
170
|
+
|
|
171
|
+
This toolkit is designed to be extended with more service modules:
|
|
172
|
+
|
|
173
|
+
- **S3 Media** — Available now
|
|
174
|
+
- **Email** — Coming soon
|
|
175
|
+
- **More** — Additional cloud services planned
|
|
176
|
+
|
|
177
|
+
## Development
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
# Install dependencies
|
|
181
|
+
npm install
|
|
182
|
+
|
|
183
|
+
# Build
|
|
184
|
+
npm run build
|
|
185
|
+
|
|
186
|
+
# Run structure tests
|
|
187
|
+
node test.js
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Publishing
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
npm login
|
|
194
|
+
npm publish
|
|
195
|
+
npm info cloud-service-kit
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## License
|
|
199
|
+
|
|
200
|
+
UNLICENSED
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.S3MediaClient = void 0;
|
|
4
|
+
var s3_media_client_1 = require("./s3-media-client");
|
|
5
|
+
Object.defineProperty(exports, "S3MediaClient", { enumerable: true, get: function () { return s3_media_client_1.S3MediaClient; } });
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { S3Client } from "@aws-sdk/client-s3";
|
|
2
|
+
import { AWSConfig } from "../types";
|
|
3
|
+
export declare function createS3Client(config: AWSConfig): S3Client;
|
|
4
|
+
export declare function uploadToS3(client: S3Client, bucket: string, buffer: Buffer, key: string, contentType: string): Promise<string>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createS3Client = createS3Client;
|
|
4
|
+
exports.uploadToS3 = uploadToS3;
|
|
5
|
+
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
6
|
+
function createS3Client(config) {
|
|
7
|
+
return new client_s3_1.S3Client({
|
|
8
|
+
region: config.region,
|
|
9
|
+
credentials: {
|
|
10
|
+
accessKeyId: config.accessKey,
|
|
11
|
+
secretAccessKey: config.secretKey,
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
async function uploadToS3(client, bucket, buffer, key, contentType) {
|
|
16
|
+
const command = new client_s3_1.PutObjectCommand({
|
|
17
|
+
Bucket: bucket,
|
|
18
|
+
Key: key,
|
|
19
|
+
Body: buffer,
|
|
20
|
+
ContentType: contentType,
|
|
21
|
+
});
|
|
22
|
+
await client.send(command);
|
|
23
|
+
return key;
|
|
24
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MediaModule = void 0;
|
|
4
|
+
var media_module_1 = require("./media.module");
|
|
5
|
+
Object.defineProperty(exports, "MediaModule", { enumerable: true, get: function () { return media_module_1.MediaModule; } });
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { S3Client } from "@aws-sdk/client-s3";
|
|
2
|
+
import { AWSConfig } from "../../types";
|
|
3
|
+
import { MediaUploadOptions, MediaUploadResponse } from "./media.types";
|
|
4
|
+
export declare class MediaModule {
|
|
5
|
+
private s3Client;
|
|
6
|
+
private awsConfig;
|
|
7
|
+
constructor(s3Client: S3Client, awsConfig: AWSConfig);
|
|
8
|
+
/**
|
|
9
|
+
* Fetch an image from a live URL and upload it to S3.
|
|
10
|
+
*/
|
|
11
|
+
uploadFromUrl(url: string, options?: MediaUploadOptions): Promise<MediaUploadResponse>;
|
|
12
|
+
/**
|
|
13
|
+
* Upload a buffer (e.g. from multer file upload) directly to S3.
|
|
14
|
+
*/
|
|
15
|
+
uploadBuffer(buffer: Buffer, options?: MediaUploadOptions): Promise<MediaUploadResponse>;
|
|
16
|
+
private generateKey;
|
|
17
|
+
private resolveExtension;
|
|
18
|
+
private buildS3Url;
|
|
19
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.MediaModule = void 0;
|
|
7
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const s3_client_1 = require("../../lib/s3.client");
|
|
10
|
+
class MediaModule {
|
|
11
|
+
constructor(s3Client, awsConfig) {
|
|
12
|
+
this.s3Client = s3Client;
|
|
13
|
+
this.awsConfig = awsConfig;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Fetch an image from a live URL and upload it to S3.
|
|
17
|
+
*/
|
|
18
|
+
async uploadFromUrl(url, options = {}) {
|
|
19
|
+
const response = await fetch(url);
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
throw new Error(`Failed to fetch image from URL: ${response.status} ${response.statusText}`);
|
|
22
|
+
}
|
|
23
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
24
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
25
|
+
const contentType = options.contentType ||
|
|
26
|
+
response.headers.get("content-type") ||
|
|
27
|
+
"application/octet-stream";
|
|
28
|
+
const key = options.key || this.generateKey(options.folder, url, contentType);
|
|
29
|
+
await (0, s3_client_1.uploadToS3)(this.s3Client, this.awsConfig.bucket, buffer, key, contentType);
|
|
30
|
+
return {
|
|
31
|
+
key,
|
|
32
|
+
url: this.buildS3Url(key),
|
|
33
|
+
bucket: this.awsConfig.bucket,
|
|
34
|
+
contentType,
|
|
35
|
+
size: buffer.length,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Upload a buffer (e.g. from multer file upload) directly to S3.
|
|
40
|
+
*/
|
|
41
|
+
async uploadBuffer(buffer, options = {}) {
|
|
42
|
+
const contentType = options.contentType || "application/octet-stream";
|
|
43
|
+
const key = options.key || this.generateKey(options.folder, undefined, contentType);
|
|
44
|
+
await (0, s3_client_1.uploadToS3)(this.s3Client, this.awsConfig.bucket, buffer, key, contentType);
|
|
45
|
+
return {
|
|
46
|
+
key,
|
|
47
|
+
url: this.buildS3Url(key),
|
|
48
|
+
bucket: this.awsConfig.bucket,
|
|
49
|
+
contentType,
|
|
50
|
+
size: buffer.length,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
generateKey(folder, sourceUrl, contentType) {
|
|
54
|
+
const uuid = crypto_1.default.randomUUID();
|
|
55
|
+
const ext = this.resolveExtension(sourceUrl, contentType);
|
|
56
|
+
const filename = `${uuid}${ext}`;
|
|
57
|
+
return folder ? `${folder}/${filename}` : filename;
|
|
58
|
+
}
|
|
59
|
+
resolveExtension(sourceUrl, contentType) {
|
|
60
|
+
// Try to get extension from the source URL
|
|
61
|
+
if (sourceUrl) {
|
|
62
|
+
try {
|
|
63
|
+
const pathname = new URL(sourceUrl).pathname;
|
|
64
|
+
const ext = path_1.default.extname(pathname);
|
|
65
|
+
if (ext)
|
|
66
|
+
return ext;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// invalid URL, fall through
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Fall back to content type
|
|
73
|
+
const mimeToExt = {
|
|
74
|
+
"image/jpeg": ".jpg",
|
|
75
|
+
"image/png": ".png",
|
|
76
|
+
"image/gif": ".gif",
|
|
77
|
+
"image/webp": ".webp",
|
|
78
|
+
"image/svg+xml": ".svg",
|
|
79
|
+
"image/bmp": ".bmp",
|
|
80
|
+
"image/tiff": ".tiff",
|
|
81
|
+
};
|
|
82
|
+
if (contentType && mimeToExt[contentType]) {
|
|
83
|
+
return mimeToExt[contentType];
|
|
84
|
+
}
|
|
85
|
+
return "";
|
|
86
|
+
}
|
|
87
|
+
buildS3Url(key) {
|
|
88
|
+
return `https://${this.awsConfig.bucket}.s3.${this.awsConfig.region}.amazonaws.com/${key}`;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
exports.MediaModule = MediaModule;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface MediaUploadOptions {
|
|
2
|
+
/** Custom S3 key. If omitted, a UUID-based key is auto-generated. */
|
|
3
|
+
key?: string;
|
|
4
|
+
/** S3 folder prefix (e.g. "uploads"). Ignored if `key` is provided. */
|
|
5
|
+
folder?: string;
|
|
6
|
+
/** MIME content type (e.g. "image/jpeg"). Auto-detected for URL uploads. */
|
|
7
|
+
contentType?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface MediaUploadResponse {
|
|
10
|
+
/** The S3 object key */
|
|
11
|
+
key: string;
|
|
12
|
+
/** Full S3 URL to the uploaded object */
|
|
13
|
+
url: string;
|
|
14
|
+
/** S3 bucket name */
|
|
15
|
+
bucket: string;
|
|
16
|
+
/** MIME content type of the uploaded file */
|
|
17
|
+
contentType: string;
|
|
18
|
+
/** File size in bytes */
|
|
19
|
+
size: number;
|
|
20
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.S3MediaClient = void 0;
|
|
4
|
+
const s3_client_1 = require("./lib/s3.client");
|
|
5
|
+
const media_1 = require("./modules/media");
|
|
6
|
+
class S3MediaClient {
|
|
7
|
+
constructor(config) {
|
|
8
|
+
this.s3Client = (0, s3_client_1.createS3Client)(config.aws);
|
|
9
|
+
this.media = new media_1.MediaModule(this.s3Client, config.aws);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.S3MediaClient = S3MediaClient;
|
package/dist/types.d.ts
ADDED
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cloud-service-kit",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A modular cloud service toolkit for S3 media uploads, email, and more",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"prepublishOnly": "npm run build"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"cloud",
|
|
16
|
+
"s3",
|
|
17
|
+
"media",
|
|
18
|
+
"upload",
|
|
19
|
+
"aws",
|
|
20
|
+
"toolkit"
|
|
21
|
+
],
|
|
22
|
+
"license": "UNLICENSED",
|
|
23
|
+
"private": false,
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@aws-sdk/client-s3": "^3.700.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/node": "^25.3.0",
|
|
32
|
+
"typescript": "^5.7.0"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=18.0.0"
|
|
36
|
+
}
|
|
37
|
+
}
|