@signskart/uploader 1.0.8 → 2.0.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 +196 -33
- package/dist/index.js +7 -35
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -6
- package/dist/index.mjs.map +1 -1
- package/dist/server/index.d.mts +20 -0
- package/dist/server/index.d.ts +20 -0
- package/dist/server/index.js +42 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/index.mjs +40 -0
- package/dist/server/index.mjs.map +1 -0
- package/package.json +15 -7
package/README.md
CHANGED
|
@@ -1,21 +1,41 @@
|
|
|
1
|
-
|
|
1
|
+
Here is your **fully updated, production-ready README** including:
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
* ✅ Client + Server usage
|
|
4
|
+
* ✅ Proper S3 presign setup
|
|
5
|
+
* ✅ Next.js backend example
|
|
6
|
+
* ✅ Express backend example
|
|
7
|
+
* ✅ Architecture explanation
|
|
8
|
+
* ✅ Clean professional structure
|
|
9
|
+
* ✅ v2 structure with `/server` export
|
|
4
10
|
|
|
5
|
-
|
|
11
|
+
You can replace your entire README with this.
|
|
6
12
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# 🚀 @signskart/uploader
|
|
16
|
+
|
|
17
|
+
Production-grade Upload Manager SDK by **Signskart**.
|
|
18
|
+
|
|
19
|
+
A powerful, fully-typed file upload SDK with queue management, retry logic, cancellation support, concurrency control, and multi-provider architecture (S3 + Cloudinary).
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## ✨ Features
|
|
24
|
+
|
|
25
|
+
* 🚀 Upload queue system
|
|
26
|
+
* 🔁 Automatic retry with exponential backoff
|
|
27
|
+
* 📊 Real-time progress tracking
|
|
28
|
+
* ❌ Cancel uploads (AbortController support)
|
|
29
|
+
* ⚡ Concurrency control
|
|
30
|
+
* ☁ Multi-provider support (Amazon S3, Cloudinary)
|
|
31
|
+
* 🧠 Fully typed (TypeScript)
|
|
32
|
+
* 🌍 Works with React, Vue, Next.js, Vite, vanilla JS
|
|
33
|
+
* 🔐 Secure S3 presigned upload support
|
|
34
|
+
* 🖥 Optional server helper included
|
|
15
35
|
|
|
16
36
|
---
|
|
17
37
|
|
|
18
|
-
|
|
38
|
+
# 📦 Installation
|
|
19
39
|
|
|
20
40
|
```bash
|
|
21
41
|
npm install @signskart/uploader
|
|
@@ -29,19 +49,37 @@ yarn add @signskart/uploader
|
|
|
29
49
|
|
|
30
50
|
---
|
|
31
51
|
|
|
52
|
+
# 🏗 Architecture
|
|
53
|
+
|
|
54
|
+
For **Amazon S3**, uploads require a backend to generate presigned URLs.
|
|
55
|
+
|
|
56
|
+
Flow:
|
|
57
|
+
|
|
58
|
+
Frontend → Backend (presign) → S3 → Frontend uploads directly
|
|
59
|
+
|
|
60
|
+
Your AWS credentials NEVER reach the browser.
|
|
61
|
+
|
|
62
|
+
Cloudinary does NOT require backend if using unsigned preset.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
32
66
|
# 🚀 Quick Start
|
|
33
67
|
|
|
34
|
-
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
# ☁ Using Amazon S3
|
|
71
|
+
|
|
72
|
+
## 1️⃣ Frontend Setup
|
|
35
73
|
|
|
36
74
|
```ts
|
|
37
75
|
import { UploadManager, S3Uploader } from '@signskart/uploader';
|
|
38
76
|
|
|
39
77
|
const uploader = new S3Uploader({
|
|
40
|
-
|
|
78
|
+
presignEndpoint: '/api/s3/presign-upload',
|
|
41
79
|
publicUrl: 'https://cdn.yoursite.com'
|
|
42
80
|
});
|
|
43
81
|
|
|
44
|
-
const manager = new UploadManager(uploader, 2);
|
|
82
|
+
const manager = new UploadManager(uploader, 2);
|
|
45
83
|
|
|
46
84
|
const task = manager.add({
|
|
47
85
|
file,
|
|
@@ -55,7 +93,70 @@ task.events.subscribe((state) => {
|
|
|
55
93
|
|
|
56
94
|
---
|
|
57
95
|
|
|
58
|
-
##
|
|
96
|
+
## 2️⃣ Backend Setup (Next.js Example)
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
// app/api/s3/presign-upload/route.ts
|
|
100
|
+
|
|
101
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
102
|
+
import { createS3PresignHandler } from '@signskart/uploader/server';
|
|
103
|
+
|
|
104
|
+
const generatePresignedUpload = createS3PresignHandler({
|
|
105
|
+
region: process.env.AWS_REGION!,
|
|
106
|
+
accessKeyId: process.env.AWS_KEY!,
|
|
107
|
+
secretAccessKey: process.env.AWS_SECRET!,
|
|
108
|
+
bucket: process.env.AWS_S3_BUCKET!,
|
|
109
|
+
publicUrl: process.env.NEXT_PUBLIC_S3_PUBLIC_URL!,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
export async function POST(req: NextRequest) {
|
|
113
|
+
try {
|
|
114
|
+
const body = await req.json();
|
|
115
|
+
const result = await generatePresignedUpload(body);
|
|
116
|
+
return NextResponse.json(result);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
return NextResponse.json(
|
|
119
|
+
{ error: 'Failed to generate presigned URL' },
|
|
120
|
+
{ status: 500 }
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## 3️⃣ Backend Setup (Express Example)
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import express from 'express';
|
|
132
|
+
import { createS3PresignHandler } from '@signskart/uploader/server';
|
|
133
|
+
|
|
134
|
+
const app = express();
|
|
135
|
+
app.use(express.json());
|
|
136
|
+
|
|
137
|
+
const generatePresignedUpload = createS3PresignHandler({
|
|
138
|
+
region: process.env.AWS_REGION!,
|
|
139
|
+
accessKeyId: process.env.AWS_KEY!,
|
|
140
|
+
secretAccessKey: process.env.AWS_SECRET!,
|
|
141
|
+
bucket: process.env.AWS_S3_BUCKET!,
|
|
142
|
+
publicUrl: process.env.S3_PUBLIC_URL!,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
app.post('/api/s3/presign-upload', async (req, res) => {
|
|
146
|
+
try {
|
|
147
|
+
const result = await generatePresignedUpload(req.body);
|
|
148
|
+
res.json(result);
|
|
149
|
+
} catch (error) {
|
|
150
|
+
res.status(500).json({ error: 'Failed to generate presigned URL' });
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
app.listen(3000);
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
# ☁ Using Cloudinary (No Backend Required)
|
|
59
160
|
|
|
60
161
|
```ts
|
|
61
162
|
import { UploadManager, CloudinaryUploader } from '@signskart/uploader';
|
|
@@ -77,18 +178,20 @@ const task = manager.add({
|
|
|
77
178
|
|
|
78
179
|
# 🧠 API Reference
|
|
79
180
|
|
|
181
|
+
---
|
|
182
|
+
|
|
80
183
|
## UploadManager
|
|
81
184
|
|
|
82
185
|
```ts
|
|
83
186
|
new UploadManager(uploader, concurrency?)
|
|
84
187
|
```
|
|
85
188
|
|
|
86
|
-
### Parameters
|
|
189
|
+
### Parameters
|
|
87
190
|
|
|
88
|
-
| Parameter
|
|
89
|
-
|
|
90
|
-
| uploader
|
|
91
|
-
| concurrency | number
|
|
191
|
+
| Parameter | Type | Default |
|
|
192
|
+
| ----------- | ------------ | -------- |
|
|
193
|
+
| uploader | BaseUploader | required |
|
|
194
|
+
| concurrency | number | 3 |
|
|
92
195
|
|
|
93
196
|
---
|
|
94
197
|
|
|
@@ -100,12 +203,12 @@ Returned from:
|
|
|
100
203
|
const task = manager.add(options);
|
|
101
204
|
```
|
|
102
205
|
|
|
103
|
-
### Properties
|
|
206
|
+
### Properties
|
|
104
207
|
|
|
105
|
-
|
|
106
|
-
|
|
208
|
+
* `task.state`
|
|
209
|
+
* `task.events.subscribe()`
|
|
107
210
|
|
|
108
|
-
### Methods
|
|
211
|
+
### Methods
|
|
109
212
|
|
|
110
213
|
```ts
|
|
111
214
|
task.start()
|
|
@@ -129,9 +232,10 @@ task.cancel()
|
|
|
129
232
|
|
|
130
233
|
# 🔁 Retry Logic
|
|
131
234
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
235
|
+
* Automatic retry
|
|
236
|
+
* Exponential backoff
|
|
237
|
+
* Default max retries: 2
|
|
238
|
+
* Cancels if AbortController triggered
|
|
135
239
|
|
|
136
240
|
---
|
|
137
241
|
|
|
@@ -147,13 +251,25 @@ task.cancel();
|
|
|
147
251
|
|
|
148
252
|
```ts
|
|
149
253
|
task.events.subscribe((state) => {
|
|
150
|
-
console.log(state.progress);
|
|
254
|
+
console.log(state.progress, state.status);
|
|
151
255
|
});
|
|
152
256
|
```
|
|
153
257
|
|
|
258
|
+
State structure:
|
|
259
|
+
|
|
260
|
+
```ts
|
|
261
|
+
{
|
|
262
|
+
id: string;
|
|
263
|
+
progress: number;
|
|
264
|
+
status: 'queued' | 'uploading' | 'success' | 'error' | 'cancelled';
|
|
265
|
+
error?: string;
|
|
266
|
+
response?: UploadResponse;
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
154
270
|
---
|
|
155
271
|
|
|
156
|
-
#
|
|
272
|
+
# ⚛ Example React Usage
|
|
157
273
|
|
|
158
274
|
```tsx
|
|
159
275
|
const handleUpload = (file: File) => {
|
|
@@ -167,13 +283,60 @@ const handleUpload = (file: File) => {
|
|
|
167
283
|
|
|
168
284
|
---
|
|
169
285
|
|
|
286
|
+
# 🔐 Security Notes (Important)
|
|
287
|
+
|
|
288
|
+
* AWS credentials must NEVER be exposed to frontend.
|
|
289
|
+
* Always generate presigned URLs server-side.
|
|
290
|
+
* Cloudinary unsigned preset must have restricted permissions.
|
|
291
|
+
* Set proper S3 bucket CORS configuration.
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
170
295
|
# 🛠 Requirements
|
|
171
296
|
|
|
172
|
-
|
|
173
|
-
|
|
297
|
+
* Modern browser (AbortController support)
|
|
298
|
+
* Node.js 18+ for server helper
|
|
299
|
+
* Backend endpoint for S3 presign (if using S3)
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
# 📦 Package Exports
|
|
304
|
+
|
|
305
|
+
Client:
|
|
306
|
+
|
|
307
|
+
```ts
|
|
308
|
+
import { UploadManager } from '@signskart/uploader';
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Server helper:
|
|
312
|
+
|
|
313
|
+
```ts
|
|
314
|
+
import { createS3PresignHandler } from '@signskart/uploader/server';
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
# 📈 Roadmap
|
|
320
|
+
|
|
321
|
+
* Multipart uploads (100MB+)
|
|
322
|
+
* Image compression plugin
|
|
323
|
+
* Validation middleware
|
|
324
|
+
* Signed download URLs
|
|
325
|
+
* React hooks wrapper
|
|
174
326
|
|
|
175
327
|
---
|
|
176
328
|
|
|
177
329
|
# 📜 License
|
|
178
330
|
|
|
179
|
-
MIT © Signskart
|
|
331
|
+
MIT © Signskart
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
If you want next, I can:
|
|
336
|
+
|
|
337
|
+
* Turn this into an elite-level open source README (badges, diagrams, examples, comparison table)
|
|
338
|
+
* Prepare it for GitHub launch
|
|
339
|
+
* Write marketing description for npm
|
|
340
|
+
* Add proper semantic versioning strategy
|
|
341
|
+
|
|
342
|
+
Tell me your next move.
|
package/dist/index.js
CHANGED
|
@@ -1,31 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/index.ts
|
|
21
|
-
var index_exports = {};
|
|
22
|
-
__export(index_exports, {
|
|
23
|
-
CloudinaryUploader: () => CloudinaryUploader,
|
|
24
|
-
S3Uploader: () => S3Uploader,
|
|
25
|
-
UploadManager: () => UploadManager,
|
|
26
|
-
UploadTask: () => UploadTask
|
|
27
|
-
});
|
|
28
|
-
module.exports = __toCommonJS(index_exports);
|
|
1
|
+
'use strict';
|
|
29
2
|
|
|
30
3
|
// src/core/EventEmitter.ts
|
|
31
4
|
var EventEmitter = class {
|
|
@@ -208,11 +181,10 @@ var CloudinaryUploader = class extends BaseUploader {
|
|
|
208
181
|
});
|
|
209
182
|
}
|
|
210
183
|
};
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
});
|
|
184
|
+
|
|
185
|
+
exports.CloudinaryUploader = CloudinaryUploader;
|
|
186
|
+
exports.S3Uploader = S3Uploader;
|
|
187
|
+
exports.UploadManager = UploadManager;
|
|
188
|
+
exports.UploadTask = UploadTask;
|
|
189
|
+
//# sourceMappingURL=index.js.map
|
|
218
190
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/core/EventEmitter.ts","../src/core/UploadTask.ts","../src/core/UploadManager.ts","../src/core/BaseUploader.ts","../src/providers/S3Uploader.ts","../src/providers/CloudinaryUploader.ts"],"sourcesContent":["export * from './core/types';\nexport * from './core/UploadManager';\nexport * from './core/UploadTask';\nexport * from './providers/S3Uploader';\nexport * from './providers/CloudinaryUploader';","type Listener<T> = (payload: T) => void;\n\nexport class EventEmitter<T> {\n private listeners: Listener<T>[] = [];\n\n subscribe(listener: Listener<T>) {\n this.listeners.push(listener);\n return () => {\n this.listeners = this.listeners.filter(l => l !== listener);\n };\n }\n\n emit(payload: T) {\n this.listeners.forEach(listener => listener(payload));\n }\n}","import { BaseUploader } from './BaseUploader';\nimport { UploadOptions, UploadTaskState } from './types';\nimport { EventEmitter } from './EventEmitter';\n\nexport class UploadTask {\n public state: UploadTaskState;\n public events = new EventEmitter<UploadTaskState>();\n private abortController = new AbortController();\n private retries = 0;\n\n constructor(\n private uploader: BaseUploader,\n private options: UploadOptions,\n private maxRetries = 2,\n private retryDelay = 500\n ) {\n this.state = {\n id: crypto.randomUUID(),\n progress: 0,\n status: 'queued'\n };\n }\n\n async start(): Promise<void> {\n this.update({ status: 'uploading' });\n\n while (this.retries <= this.maxRetries) {\n try {\n const response = await this.uploader.upload(\n this.options,\n progress => this.update({ progress }),\n this.abortController.signal\n );\n\n this.update({ status: 'success', progress: 100, response });\n return;\n } catch (error: unknown) {\n if (this.abortController.signal.aborted) {\n this.update({ status: 'cancelled' });\n return;\n }\n\n const message = error instanceof Error ? error.message : 'Unknown upload error';\n\n if (this.retries >= this.maxRetries) {\n this.update({ status: 'error', error: message });\n return;\n }\n\n this.retries++;\n await this.sleep(this.retryDelay * Math.pow(2, this.retries - 1));\n }\n }\n }\n\n cancel() {\n this.abortController.abort();\n this.update({ status: 'cancelled' });\n }\n\n private update(update: Partial<UploadTaskState>) {\n this.state = { ...this.state, ...update };\n this.events.emit(this.state);\n }\n\n private sleep(ms: number) {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}","import { BaseUploader } from './BaseUploader';\nimport { UploadOptions } from './types';\nimport { UploadTask } from './UploadTask';\n\nexport class UploadManager {\n private queue: UploadTask[] = [];\n private active = 0;\n\n constructor(private uploader: BaseUploader, private concurrency = 3) { }\n\n add(options: UploadOptions) {\n const task = new UploadTask(this.uploader, options);\n this.queue.push(task);\n this.process();\n return task;\n }\n\n private async process() {\n if (this.active >= this.concurrency) return;\n\n const next = this.queue.find(t => t.state.status === 'queued');\n if (!next) return;\n\n this.active++;\n await next.start();\n this.active--;\n this.process();\n }\n}","import { UploadOptions, UploadResponse } from './types';\n\nexport abstract class BaseUploader {\n abstract upload(options: UploadOptions, onProgress: (percent: number) => void, signal?: AbortSignal): Promise<UploadResponse>;\n}","import { BaseUploader } from '../core/BaseUploader';\nimport { UploadOptions, UploadResponse } from '../core/types';\n\ninterface S3Config {\n apiBaseUrl: string;\n publicUrl: string;\n}\n\nexport class S3Uploader extends BaseUploader {\n constructor(private config: S3Config) {\n super();\n }\n\n async upload(\n options: UploadOptions,\n onProgress: (percent: number) => void,\n signal?: AbortSignal\n ): Promise<UploadResponse> {\n const presignRes = await fetch(`${this.config.apiBaseUrl}/api/s3/presign-upload`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n fileName: options.fileName || options.file.name,\n folder: options.folder,\n contentType: options.file.type\n })\n });\n\n if (!presignRes.ok) throw new Error('Failed to get presigned URL');\n\n const { signedUrl, key } = await presignRes.json();\n\n if (!signedUrl || !key) throw new Error('Invalid presign response');\n\n return new Promise<UploadResponse>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.upload.onprogress = event => {\n if (event.lengthComputable) {\n onProgress(Math.round((event.loaded / event.total) * 100));\n }\n };\n\n xhr.onload = () => {\n if (xhr.status === 200) {\n resolve({\n url: `${this.config.publicUrl}/${key}`,\n provider: 's3',\n key,\n });\n } else {\n reject(new Error(`S3 upload failed with status ${xhr.status}`));\n }\n };\n\n xhr.onerror = () => reject(new Error('S3 upload network error'));\n\n signal?.addEventListener('abort', () => {\n xhr.abort();\n reject(new Error('Upload cancelled'));\n });\n\n xhr.open('PUT', signedUrl);\n xhr.setRequestHeader('Content-Type', options.file.type);\n xhr.send(options.file);\n });\n }\n}","import { BaseUploader } from '../core/BaseUploader';\nimport { UploadOptions, UploadResponse } from '../core/types';\n\ninterface CloudinaryConfig {\n cloudName: string;\n uploadPreset: string;\n}\n\nexport class CloudinaryUploader extends BaseUploader {\n constructor(private config: CloudinaryConfig) {\n super();\n }\n\n async upload(\n options: UploadOptions,\n onProgress: (percent: number) => void\n ): Promise<UploadResponse> {\n const formData = new FormData();\n formData.append('file', options.file);\n formData.append('upload_preset', this.config.uploadPreset);\n formData.append('folder', options.folder);\n\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.upload.onprogress = event => {\n if (event.lengthComputable) {\n onProgress(Math.round((event.loaded / event.total) * 100));\n }\n };\n\n xhr.onload = () => {\n const data = JSON.parse(xhr.responseText);\n if (xhr.status === 200 && data.secure_url) {\n resolve({ url: data.secure_url, provider: 'cloudinary' });\n } else {\n reject(new Error('Cloudinary upload failed'));\n }\n };\n\n xhr.onerror = () => reject(new Error('Cloudinary upload failed'));\n\n xhr.open('POST', `https://api.cloudinary.com/v1_1/${this.config.cloudName}/upload`);\n xhr.send(formData);\n });\n }\n}"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/core/EventEmitter.ts","../src/core/UploadTask.ts","../src/core/UploadManager.ts","../src/core/BaseUploader.ts","../src/providers/S3Uploader.ts","../src/providers/CloudinaryUploader.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["type Listener<T> = (payload: T) => void;\n\nexport class EventEmitter<T> {\n private listeners: Listener<T>[] = [];\n\n subscribe(listener: Listener<T>) {\n this.listeners.push(listener);\n return () => {\n this.listeners = this.listeners.filter(l => l !== listener);\n };\n }\n\n emit(payload: T) {\n this.listeners.forEach(listener => listener(payload));\n }\n}","import { BaseUploader } from './BaseUploader';\nimport { UploadOptions, UploadTaskState } from './types';\nimport { EventEmitter } from './EventEmitter';\n\nexport class UploadTask {\n public state: UploadTaskState;\n public events = new EventEmitter<UploadTaskState>();\n private abortController = new AbortController();\n private retries = 0;\n\n constructor(\n private uploader: BaseUploader,\n private options: UploadOptions,\n private maxRetries = 2,\n private retryDelay = 500\n ) {\n this.state = {\n id: crypto.randomUUID(),\n progress: 0,\n status: 'queued'\n };\n }\n\n async start(): Promise<void> {\n this.update({ status: 'uploading' });\n\n while (this.retries <= this.maxRetries) {\n try {\n const response = await this.uploader.upload(\n this.options,\n progress => this.update({ progress }),\n this.abortController.signal\n );\n\n this.update({ status: 'success', progress: 100, response });\n return;\n } catch (error: unknown) {\n if (this.abortController.signal.aborted) {\n this.update({ status: 'cancelled' });\n return;\n }\n\n const message = error instanceof Error ? error.message : 'Unknown upload error';\n\n if (this.retries >= this.maxRetries) {\n this.update({ status: 'error', error: message });\n return;\n }\n\n this.retries++;\n await this.sleep(this.retryDelay * Math.pow(2, this.retries - 1));\n }\n }\n }\n\n cancel() {\n this.abortController.abort();\n this.update({ status: 'cancelled' });\n }\n\n private update(update: Partial<UploadTaskState>) {\n this.state = { ...this.state, ...update };\n this.events.emit(this.state);\n }\n\n private sleep(ms: number) {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}","import { BaseUploader } from './BaseUploader';\nimport { UploadOptions } from './types';\nimport { UploadTask } from './UploadTask';\n\nexport class UploadManager {\n private queue: UploadTask[] = [];\n private active = 0;\n\n constructor(private uploader: BaseUploader, private concurrency = 3) { }\n\n add(options: UploadOptions) {\n const task = new UploadTask(this.uploader, options);\n this.queue.push(task);\n this.process();\n return task;\n }\n\n private async process() {\n if (this.active >= this.concurrency) return;\n\n const next = this.queue.find(t => t.state.status === 'queued');\n if (!next) return;\n\n this.active++;\n await next.start();\n this.active--;\n this.process();\n }\n}","import { UploadOptions, UploadResponse } from './types';\n\nexport abstract class BaseUploader {\n abstract upload(options: UploadOptions, onProgress: (percent: number) => void, signal?: AbortSignal): Promise<UploadResponse>;\n}","import { BaseUploader } from '../core/BaseUploader';\nimport { UploadOptions, UploadResponse } from '../core/types';\n\ninterface S3Config {\n apiBaseUrl: string;\n publicUrl: string;\n}\n\nexport class S3Uploader extends BaseUploader {\n constructor(private config: S3Config) {\n super();\n }\n\n async upload(\n options: UploadOptions,\n onProgress: (percent: number) => void,\n signal?: AbortSignal\n ): Promise<UploadResponse> {\n const presignRes = await fetch(`${this.config.apiBaseUrl}/api/s3/presign-upload`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n fileName: options.fileName || options.file.name,\n folder: options.folder,\n contentType: options.file.type\n })\n });\n\n if (!presignRes.ok) throw new Error('Failed to get presigned URL');\n\n const { signedUrl, key } = await presignRes.json();\n\n if (!signedUrl || !key) throw new Error('Invalid presign response');\n\n return new Promise<UploadResponse>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.upload.onprogress = event => {\n if (event.lengthComputable) {\n onProgress(Math.round((event.loaded / event.total) * 100));\n }\n };\n\n xhr.onload = () => {\n if (xhr.status === 200) {\n resolve({\n url: `${this.config.publicUrl}/${key}`,\n provider: 's3',\n key,\n });\n } else {\n reject(new Error(`S3 upload failed with status ${xhr.status}`));\n }\n };\n\n xhr.onerror = () => reject(new Error('S3 upload network error'));\n\n signal?.addEventListener('abort', () => {\n xhr.abort();\n reject(new Error('Upload cancelled'));\n });\n\n xhr.open('PUT', signedUrl);\n xhr.setRequestHeader('Content-Type', options.file.type);\n xhr.send(options.file);\n });\n }\n}","import { BaseUploader } from '../core/BaseUploader';\nimport { UploadOptions, UploadResponse } from '../core/types';\n\ninterface CloudinaryConfig {\n cloudName: string;\n uploadPreset: string;\n}\n\nexport class CloudinaryUploader extends BaseUploader {\n constructor(private config: CloudinaryConfig) {\n super();\n }\n\n async upload(\n options: UploadOptions,\n onProgress: (percent: number) => void\n ): Promise<UploadResponse> {\n const formData = new FormData();\n formData.append('file', options.file);\n formData.append('upload_preset', this.config.uploadPreset);\n formData.append('folder', options.folder);\n\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.upload.onprogress = event => {\n if (event.lengthComputable) {\n onProgress(Math.round((event.loaded / event.total) * 100));\n }\n };\n\n xhr.onload = () => {\n const data = JSON.parse(xhr.responseText);\n if (xhr.status === 200 && data.secure_url) {\n resolve({ url: data.secure_url, provider: 'cloudinary' });\n } else {\n reject(new Error('Cloudinary upload failed'));\n }\n };\n\n xhr.onerror = () => reject(new Error('Cloudinary upload failed'));\n\n xhr.open('POST', `https://api.cloudinary.com/v1_1/${this.config.cloudName}/upload`);\n xhr.send(formData);\n });\n }\n}"]}
|
package/dist/index.mjs
CHANGED
|
@@ -179,10 +179,7 @@ var CloudinaryUploader = class extends BaseUploader {
|
|
|
179
179
|
});
|
|
180
180
|
}
|
|
181
181
|
};
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
UploadManager,
|
|
186
|
-
UploadTask
|
|
187
|
-
};
|
|
182
|
+
|
|
183
|
+
export { CloudinaryUploader, S3Uploader, UploadManager, UploadTask };
|
|
184
|
+
//# sourceMappingURL=index.mjs.map
|
|
188
185
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/EventEmitter.ts","../src/core/UploadTask.ts","../src/core/UploadManager.ts","../src/core/BaseUploader.ts","../src/providers/S3Uploader.ts","../src/providers/CloudinaryUploader.ts"],"sourcesContent":["type Listener<T> = (payload: T) => void;\n\nexport class EventEmitter<T> {\n private listeners: Listener<T>[] = [];\n\n subscribe(listener: Listener<T>) {\n this.listeners.push(listener);\n return () => {\n this.listeners = this.listeners.filter(l => l !== listener);\n };\n }\n\n emit(payload: T) {\n this.listeners.forEach(listener => listener(payload));\n }\n}","import { BaseUploader } from './BaseUploader';\nimport { UploadOptions, UploadTaskState } from './types';\nimport { EventEmitter } from './EventEmitter';\n\nexport class UploadTask {\n public state: UploadTaskState;\n public events = new EventEmitter<UploadTaskState>();\n private abortController = new AbortController();\n private retries = 0;\n\n constructor(\n private uploader: BaseUploader,\n private options: UploadOptions,\n private maxRetries = 2,\n private retryDelay = 500\n ) {\n this.state = {\n id: crypto.randomUUID(),\n progress: 0,\n status: 'queued'\n };\n }\n\n async start(): Promise<void> {\n this.update({ status: 'uploading' });\n\n while (this.retries <= this.maxRetries) {\n try {\n const response = await this.uploader.upload(\n this.options,\n progress => this.update({ progress }),\n this.abortController.signal\n );\n\n this.update({ status: 'success', progress: 100, response });\n return;\n } catch (error: unknown) {\n if (this.abortController.signal.aborted) {\n this.update({ status: 'cancelled' });\n return;\n }\n\n const message = error instanceof Error ? error.message : 'Unknown upload error';\n\n if (this.retries >= this.maxRetries) {\n this.update({ status: 'error', error: message });\n return;\n }\n\n this.retries++;\n await this.sleep(this.retryDelay * Math.pow(2, this.retries - 1));\n }\n }\n }\n\n cancel() {\n this.abortController.abort();\n this.update({ status: 'cancelled' });\n }\n\n private update(update: Partial<UploadTaskState>) {\n this.state = { ...this.state, ...update };\n this.events.emit(this.state);\n }\n\n private sleep(ms: number) {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}","import { BaseUploader } from './BaseUploader';\nimport { UploadOptions } from './types';\nimport { UploadTask } from './UploadTask';\n\nexport class UploadManager {\n private queue: UploadTask[] = [];\n private active = 0;\n\n constructor(private uploader: BaseUploader, private concurrency = 3) { }\n\n add(options: UploadOptions) {\n const task = new UploadTask(this.uploader, options);\n this.queue.push(task);\n this.process();\n return task;\n }\n\n private async process() {\n if (this.active >= this.concurrency) return;\n\n const next = this.queue.find(t => t.state.status === 'queued');\n if (!next) return;\n\n this.active++;\n await next.start();\n this.active--;\n this.process();\n }\n}","import { UploadOptions, UploadResponse } from './types';\n\nexport abstract class BaseUploader {\n abstract upload(options: UploadOptions, onProgress: (percent: number) => void, signal?: AbortSignal): Promise<UploadResponse>;\n}","import { BaseUploader } from '../core/BaseUploader';\nimport { UploadOptions, UploadResponse } from '../core/types';\n\ninterface S3Config {\n apiBaseUrl: string;\n publicUrl: string;\n}\n\nexport class S3Uploader extends BaseUploader {\n constructor(private config: S3Config) {\n super();\n }\n\n async upload(\n options: UploadOptions,\n onProgress: (percent: number) => void,\n signal?: AbortSignal\n ): Promise<UploadResponse> {\n const presignRes = await fetch(`${this.config.apiBaseUrl}/api/s3/presign-upload`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n fileName: options.fileName || options.file.name,\n folder: options.folder,\n contentType: options.file.type\n })\n });\n\n if (!presignRes.ok) throw new Error('Failed to get presigned URL');\n\n const { signedUrl, key } = await presignRes.json();\n\n if (!signedUrl || !key) throw new Error('Invalid presign response');\n\n return new Promise<UploadResponse>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.upload.onprogress = event => {\n if (event.lengthComputable) {\n onProgress(Math.round((event.loaded / event.total) * 100));\n }\n };\n\n xhr.onload = () => {\n if (xhr.status === 200) {\n resolve({\n url: `${this.config.publicUrl}/${key}`,\n provider: 's3',\n key,\n });\n } else {\n reject(new Error(`S3 upload failed with status ${xhr.status}`));\n }\n };\n\n xhr.onerror = () => reject(new Error('S3 upload network error'));\n\n signal?.addEventListener('abort', () => {\n xhr.abort();\n reject(new Error('Upload cancelled'));\n });\n\n xhr.open('PUT', signedUrl);\n xhr.setRequestHeader('Content-Type', options.file.type);\n xhr.send(options.file);\n });\n }\n}","import { BaseUploader } from '../core/BaseUploader';\nimport { UploadOptions, UploadResponse } from '../core/types';\n\ninterface CloudinaryConfig {\n cloudName: string;\n uploadPreset: string;\n}\n\nexport class CloudinaryUploader extends BaseUploader {\n constructor(private config: CloudinaryConfig) {\n super();\n }\n\n async upload(\n options: UploadOptions,\n onProgress: (percent: number) => void\n ): Promise<UploadResponse> {\n const formData = new FormData();\n formData.append('file', options.file);\n formData.append('upload_preset', this.config.uploadPreset);\n formData.append('folder', options.folder);\n\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.upload.onprogress = event => {\n if (event.lengthComputable) {\n onProgress(Math.round((event.loaded / event.total) * 100));\n }\n };\n\n xhr.onload = () => {\n const data = JSON.parse(xhr.responseText);\n if (xhr.status === 200 && data.secure_url) {\n resolve({ url: data.secure_url, provider: 'cloudinary' });\n } else {\n reject(new Error('Cloudinary upload failed'));\n }\n };\n\n xhr.onerror = () => reject(new Error('Cloudinary upload failed'));\n\n xhr.open('POST', `https://api.cloudinary.com/v1_1/${this.config.cloudName}/upload`);\n xhr.send(formData);\n });\n }\n}"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/core/EventEmitter.ts","../src/core/UploadTask.ts","../src/core/UploadManager.ts","../src/core/BaseUploader.ts","../src/providers/S3Uploader.ts","../src/providers/CloudinaryUploader.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["type Listener<T> = (payload: T) => void;\n\nexport class EventEmitter<T> {\n private listeners: Listener<T>[] = [];\n\n subscribe(listener: Listener<T>) {\n this.listeners.push(listener);\n return () => {\n this.listeners = this.listeners.filter(l => l !== listener);\n };\n }\n\n emit(payload: T) {\n this.listeners.forEach(listener => listener(payload));\n }\n}","import { BaseUploader } from './BaseUploader';\nimport { UploadOptions, UploadTaskState } from './types';\nimport { EventEmitter } from './EventEmitter';\n\nexport class UploadTask {\n public state: UploadTaskState;\n public events = new EventEmitter<UploadTaskState>();\n private abortController = new AbortController();\n private retries = 0;\n\n constructor(\n private uploader: BaseUploader,\n private options: UploadOptions,\n private maxRetries = 2,\n private retryDelay = 500\n ) {\n this.state = {\n id: crypto.randomUUID(),\n progress: 0,\n status: 'queued'\n };\n }\n\n async start(): Promise<void> {\n this.update({ status: 'uploading' });\n\n while (this.retries <= this.maxRetries) {\n try {\n const response = await this.uploader.upload(\n this.options,\n progress => this.update({ progress }),\n this.abortController.signal\n );\n\n this.update({ status: 'success', progress: 100, response });\n return;\n } catch (error: unknown) {\n if (this.abortController.signal.aborted) {\n this.update({ status: 'cancelled' });\n return;\n }\n\n const message = error instanceof Error ? error.message : 'Unknown upload error';\n\n if (this.retries >= this.maxRetries) {\n this.update({ status: 'error', error: message });\n return;\n }\n\n this.retries++;\n await this.sleep(this.retryDelay * Math.pow(2, this.retries - 1));\n }\n }\n }\n\n cancel() {\n this.abortController.abort();\n this.update({ status: 'cancelled' });\n }\n\n private update(update: Partial<UploadTaskState>) {\n this.state = { ...this.state, ...update };\n this.events.emit(this.state);\n }\n\n private sleep(ms: number) {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}","import { BaseUploader } from './BaseUploader';\nimport { UploadOptions } from './types';\nimport { UploadTask } from './UploadTask';\n\nexport class UploadManager {\n private queue: UploadTask[] = [];\n private active = 0;\n\n constructor(private uploader: BaseUploader, private concurrency = 3) { }\n\n add(options: UploadOptions) {\n const task = new UploadTask(this.uploader, options);\n this.queue.push(task);\n this.process();\n return task;\n }\n\n private async process() {\n if (this.active >= this.concurrency) return;\n\n const next = this.queue.find(t => t.state.status === 'queued');\n if (!next) return;\n\n this.active++;\n await next.start();\n this.active--;\n this.process();\n }\n}","import { UploadOptions, UploadResponse } from './types';\n\nexport abstract class BaseUploader {\n abstract upload(options: UploadOptions, onProgress: (percent: number) => void, signal?: AbortSignal): Promise<UploadResponse>;\n}","import { BaseUploader } from '../core/BaseUploader';\nimport { UploadOptions, UploadResponse } from '../core/types';\n\ninterface S3Config {\n apiBaseUrl: string;\n publicUrl: string;\n}\n\nexport class S3Uploader extends BaseUploader {\n constructor(private config: S3Config) {\n super();\n }\n\n async upload(\n options: UploadOptions,\n onProgress: (percent: number) => void,\n signal?: AbortSignal\n ): Promise<UploadResponse> {\n const presignRes = await fetch(`${this.config.apiBaseUrl}/api/s3/presign-upload`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n fileName: options.fileName || options.file.name,\n folder: options.folder,\n contentType: options.file.type\n })\n });\n\n if (!presignRes.ok) throw new Error('Failed to get presigned URL');\n\n const { signedUrl, key } = await presignRes.json();\n\n if (!signedUrl || !key) throw new Error('Invalid presign response');\n\n return new Promise<UploadResponse>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.upload.onprogress = event => {\n if (event.lengthComputable) {\n onProgress(Math.round((event.loaded / event.total) * 100));\n }\n };\n\n xhr.onload = () => {\n if (xhr.status === 200) {\n resolve({\n url: `${this.config.publicUrl}/${key}`,\n provider: 's3',\n key,\n });\n } else {\n reject(new Error(`S3 upload failed with status ${xhr.status}`));\n }\n };\n\n xhr.onerror = () => reject(new Error('S3 upload network error'));\n\n signal?.addEventListener('abort', () => {\n xhr.abort();\n reject(new Error('Upload cancelled'));\n });\n\n xhr.open('PUT', signedUrl);\n xhr.setRequestHeader('Content-Type', options.file.type);\n xhr.send(options.file);\n });\n }\n}","import { BaseUploader } from '../core/BaseUploader';\nimport { UploadOptions, UploadResponse } from '../core/types';\n\ninterface CloudinaryConfig {\n cloudName: string;\n uploadPreset: string;\n}\n\nexport class CloudinaryUploader extends BaseUploader {\n constructor(private config: CloudinaryConfig) {\n super();\n }\n\n async upload(\n options: UploadOptions,\n onProgress: (percent: number) => void\n ): Promise<UploadResponse> {\n const formData = new FormData();\n formData.append('file', options.file);\n formData.append('upload_preset', this.config.uploadPreset);\n formData.append('folder', options.folder);\n\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.upload.onprogress = event => {\n if (event.lengthComputable) {\n onProgress(Math.round((event.loaded / event.total) * 100));\n }\n };\n\n xhr.onload = () => {\n const data = JSON.parse(xhr.responseText);\n if (xhr.status === 200 && data.secure_url) {\n resolve({ url: data.secure_url, provider: 'cloudinary' });\n } else {\n reject(new Error('Cloudinary upload failed'));\n }\n };\n\n xhr.onerror = () => reject(new Error('Cloudinary upload failed'));\n\n xhr.open('POST', `https://api.cloudinary.com/v1_1/${this.config.cloudName}/upload`);\n xhr.send(formData);\n });\n }\n}"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
interface PresignConfig {
|
|
2
|
+
region: string;
|
|
3
|
+
accessKeyId: string;
|
|
4
|
+
secretAccessKey: string;
|
|
5
|
+
bucket: string;
|
|
6
|
+
publicUrl: string;
|
|
7
|
+
expiresIn?: number;
|
|
8
|
+
}
|
|
9
|
+
interface PresignRequest {
|
|
10
|
+
fileName: string;
|
|
11
|
+
contentType: string;
|
|
12
|
+
folder?: string;
|
|
13
|
+
}
|
|
14
|
+
declare function createS3PresignHandler(config: PresignConfig): ({ fileName, contentType, folder, }: PresignRequest) => Promise<{
|
|
15
|
+
signedUrl: string;
|
|
16
|
+
key: string;
|
|
17
|
+
publicUrl: string;
|
|
18
|
+
}>;
|
|
19
|
+
|
|
20
|
+
export { type PresignConfig, type PresignRequest, createS3PresignHandler };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
interface PresignConfig {
|
|
2
|
+
region: string;
|
|
3
|
+
accessKeyId: string;
|
|
4
|
+
secretAccessKey: string;
|
|
5
|
+
bucket: string;
|
|
6
|
+
publicUrl: string;
|
|
7
|
+
expiresIn?: number;
|
|
8
|
+
}
|
|
9
|
+
interface PresignRequest {
|
|
10
|
+
fileName: string;
|
|
11
|
+
contentType: string;
|
|
12
|
+
folder?: string;
|
|
13
|
+
}
|
|
14
|
+
declare function createS3PresignHandler(config: PresignConfig): ({ fileName, contentType, folder, }: PresignRequest) => Promise<{
|
|
15
|
+
signedUrl: string;
|
|
16
|
+
key: string;
|
|
17
|
+
publicUrl: string;
|
|
18
|
+
}>;
|
|
19
|
+
|
|
20
|
+
export { type PresignConfig, type PresignRequest, createS3PresignHandler };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var clientS3 = require('@aws-sdk/client-s3');
|
|
4
|
+
var s3RequestPresigner = require('@aws-sdk/s3-request-presigner');
|
|
5
|
+
|
|
6
|
+
// src/server/createS3PresignHandler.ts
|
|
7
|
+
function createS3PresignHandler(config) {
|
|
8
|
+
const s3 = new clientS3.S3Client({
|
|
9
|
+
region: config.region,
|
|
10
|
+
credentials: {
|
|
11
|
+
accessKeyId: config.accessKeyId,
|
|
12
|
+
secretAccessKey: config.secretAccessKey
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
return async function generatePresignedUpload({
|
|
16
|
+
fileName,
|
|
17
|
+
contentType,
|
|
18
|
+
folder
|
|
19
|
+
}) {
|
|
20
|
+
if (!fileName || !contentType) {
|
|
21
|
+
throw new Error("fileName and contentType are required");
|
|
22
|
+
}
|
|
23
|
+
const key = `${folder || "uploads"}/${Date.now()}-${fileName}`;
|
|
24
|
+
const command = new clientS3.PutObjectCommand({
|
|
25
|
+
Bucket: config.bucket,
|
|
26
|
+
Key: key,
|
|
27
|
+
ContentType: contentType
|
|
28
|
+
});
|
|
29
|
+
const signedUrl = await s3RequestPresigner.getSignedUrl(s3, command, {
|
|
30
|
+
expiresIn: config.expiresIn ?? 300
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
signedUrl,
|
|
34
|
+
key,
|
|
35
|
+
publicUrl: `${config.publicUrl}/${key}`
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
exports.createS3PresignHandler = createS3PresignHandler;
|
|
41
|
+
//# sourceMappingURL=index.js.map
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/server/createS3PresignHandler.ts"],"names":["S3Client","PutObjectCommand","getSignedUrl"],"mappings":";;;;;;AAkBO,SAAS,uBAAuB,MAAA,EAAuB;AAC1D,EAAA,MAAM,EAAA,GAAK,IAAIA,iBAAA,CAAS;AAAA,IACpB,QAAQ,MAAA,CAAO,MAAA;AAAA,IACf,WAAA,EAAa;AAAA,MACT,aAAa,MAAA,CAAO,WAAA;AAAA,MACpB,iBAAiB,MAAA,CAAO;AAAA;AAC5B,GACH,CAAA;AAED,EAAA,OAAO,eAAe,uBAAA,CAAwB;AAAA,IAC1C,QAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACJ,EAAmB;AACf,IAAA,IAAI,CAAC,QAAA,IAAY,CAAC,WAAA,EAAa;AAC3B,MAAA,MAAM,IAAI,MAAM,uCAAuC,CAAA;AAAA,IAC3D;AAEA,IAAA,MAAM,GAAA,GAAM,GAAG,MAAA,IAAU,SAAS,IAAI,IAAA,CAAK,GAAA,EAAK,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA;AAE5D,IAAA,MAAM,OAAA,GAAU,IAAIC,yBAAA,CAAiB;AAAA,MACjC,QAAQ,MAAA,CAAO,MAAA;AAAA,MACf,GAAA,EAAK,GAAA;AAAA,MACL,WAAA,EAAa;AAAA,KAChB,CAAA;AAED,IAAA,MAAM,SAAA,GAAY,MAAMC,+BAAA,CAAa,EAAA,EAAI,OAAA,EAAS;AAAA,MAC9C,SAAA,EAAW,OAAO,SAAA,IAAa;AAAA,KAClC,CAAA;AAED,IAAA,OAAO;AAAA,MACH,SAAA;AAAA,MACA,GAAA;AAAA,MACA,SAAA,EAAW,CAAA,EAAG,MAAA,CAAO,SAAS,IAAI,GAAG,CAAA;AAAA,KACzC;AAAA,EACJ,CAAA;AACJ","file":"index.js","sourcesContent":["import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\n\nexport interface PresignConfig {\n region: string;\n accessKeyId: string;\n secretAccessKey: string;\n bucket: string;\n publicUrl: string;\n expiresIn?: number;\n}\n\nexport interface PresignRequest {\n fileName: string;\n contentType: string;\n folder?: string;\n}\n\nexport function createS3PresignHandler(config: PresignConfig) {\n const s3 = new S3Client({\n region: config.region,\n credentials: {\n accessKeyId: config.accessKeyId,\n secretAccessKey: config.secretAccessKey,\n },\n });\n\n return async function generatePresignedUpload({\n fileName,\n contentType,\n folder,\n }: PresignRequest) {\n if (!fileName || !contentType) {\n throw new Error('fileName and contentType are required');\n }\n\n const key = `${folder || 'uploads'}/${Date.now()}-${fileName}`;\n\n const command = new PutObjectCommand({\n Bucket: config.bucket,\n Key: key,\n ContentType: contentType,\n });\n\n const signedUrl = await getSignedUrl(s3, command, {\n expiresIn: config.expiresIn ?? 300,\n });\n\n return {\n signedUrl,\n key,\n publicUrl: `${config.publicUrl}/${key}`,\n };\n };\n}"]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
|
|
2
|
+
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
|
3
|
+
|
|
4
|
+
// src/server/createS3PresignHandler.ts
|
|
5
|
+
function createS3PresignHandler(config) {
|
|
6
|
+
const s3 = new S3Client({
|
|
7
|
+
region: config.region,
|
|
8
|
+
credentials: {
|
|
9
|
+
accessKeyId: config.accessKeyId,
|
|
10
|
+
secretAccessKey: config.secretAccessKey
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
return async function generatePresignedUpload({
|
|
14
|
+
fileName,
|
|
15
|
+
contentType,
|
|
16
|
+
folder
|
|
17
|
+
}) {
|
|
18
|
+
if (!fileName || !contentType) {
|
|
19
|
+
throw new Error("fileName and contentType are required");
|
|
20
|
+
}
|
|
21
|
+
const key = `${folder || "uploads"}/${Date.now()}-${fileName}`;
|
|
22
|
+
const command = new PutObjectCommand({
|
|
23
|
+
Bucket: config.bucket,
|
|
24
|
+
Key: key,
|
|
25
|
+
ContentType: contentType
|
|
26
|
+
});
|
|
27
|
+
const signedUrl = await getSignedUrl(s3, command, {
|
|
28
|
+
expiresIn: config.expiresIn ?? 300
|
|
29
|
+
});
|
|
30
|
+
return {
|
|
31
|
+
signedUrl,
|
|
32
|
+
key,
|
|
33
|
+
publicUrl: `${config.publicUrl}/${key}`
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export { createS3PresignHandler };
|
|
39
|
+
//# sourceMappingURL=index.mjs.map
|
|
40
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/server/createS3PresignHandler.ts"],"names":[],"mappings":";;;;AAkBO,SAAS,uBAAuB,MAAA,EAAuB;AAC1D,EAAA,MAAM,EAAA,GAAK,IAAI,QAAA,CAAS;AAAA,IACpB,QAAQ,MAAA,CAAO,MAAA;AAAA,IACf,WAAA,EAAa;AAAA,MACT,aAAa,MAAA,CAAO,WAAA;AAAA,MACpB,iBAAiB,MAAA,CAAO;AAAA;AAC5B,GACH,CAAA;AAED,EAAA,OAAO,eAAe,uBAAA,CAAwB;AAAA,IAC1C,QAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACJ,EAAmB;AACf,IAAA,IAAI,CAAC,QAAA,IAAY,CAAC,WAAA,EAAa;AAC3B,MAAA,MAAM,IAAI,MAAM,uCAAuC,CAAA;AAAA,IAC3D;AAEA,IAAA,MAAM,GAAA,GAAM,GAAG,MAAA,IAAU,SAAS,IAAI,IAAA,CAAK,GAAA,EAAK,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA;AAE5D,IAAA,MAAM,OAAA,GAAU,IAAI,gBAAA,CAAiB;AAAA,MACjC,QAAQ,MAAA,CAAO,MAAA;AAAA,MACf,GAAA,EAAK,GAAA;AAAA,MACL,WAAA,EAAa;AAAA,KAChB,CAAA;AAED,IAAA,MAAM,SAAA,GAAY,MAAM,YAAA,CAAa,EAAA,EAAI,OAAA,EAAS;AAAA,MAC9C,SAAA,EAAW,OAAO,SAAA,IAAa;AAAA,KAClC,CAAA;AAED,IAAA,OAAO;AAAA,MACH,SAAA;AAAA,MACA,GAAA;AAAA,MACA,SAAA,EAAW,CAAA,EAAG,MAAA,CAAO,SAAS,IAAI,GAAG,CAAA;AAAA,KACzC;AAAA,EACJ,CAAA;AACJ","file":"index.mjs","sourcesContent":["import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\n\nexport interface PresignConfig {\n region: string;\n accessKeyId: string;\n secretAccessKey: string;\n bucket: string;\n publicUrl: string;\n expiresIn?: number;\n}\n\nexport interface PresignRequest {\n fileName: string;\n contentType: string;\n folder?: string;\n}\n\nexport function createS3PresignHandler(config: PresignConfig) {\n const s3 = new S3Client({\n region: config.region,\n credentials: {\n accessKeyId: config.accessKeyId,\n secretAccessKey: config.secretAccessKey,\n },\n });\n\n return async function generatePresignedUpload({\n fileName,\n contentType,\n folder,\n }: PresignRequest) {\n if (!fileName || !contentType) {\n throw new Error('fileName and contentType are required');\n }\n\n const key = `${folder || 'uploads'}/${Date.now()}-${fileName}`;\n\n const command = new PutObjectCommand({\n Bucket: config.bucket,\n Key: key,\n ContentType: contentType,\n });\n\n const signedUrl = await getSignedUrl(s3, command, {\n expiresIn: config.expiresIn ?? 300,\n });\n\n return {\n signedUrl,\n key,\n publicUrl: `${config.publicUrl}/${key}`,\n };\n };\n}"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signskart/uploader",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Production-grade upload manager SDK with queue, progress tracking, retry logic, and multi-provider support (S3, Cloudinary).",
|
|
3
|
+
"version": "2.0.2",
|
|
4
|
+
"description": "Production-grade upload manager SDK with queue, progress tracking, retry logic, cancellation, and multi-provider support (S3, Cloudinary).",
|
|
5
5
|
"author": "Signskart",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "dist/index.cjs",
|
|
@@ -14,12 +14,24 @@
|
|
|
14
14
|
".": {
|
|
15
15
|
"import": "./dist/index.js",
|
|
16
16
|
"require": "./dist/index.cjs"
|
|
17
|
+
},
|
|
18
|
+
"./server": {
|
|
19
|
+
"import": "./dist/server/index.js",
|
|
20
|
+
"require": "./dist/server/index.cjs"
|
|
17
21
|
}
|
|
18
22
|
},
|
|
19
23
|
"scripts": {
|
|
20
24
|
"build": "tsup",
|
|
21
25
|
"prepublishOnly": "npm run build"
|
|
22
26
|
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@aws-sdk/client-s3": "^3.540.0",
|
|
29
|
+
"@aws-sdk/s3-request-presigner": "^3.540.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"tsup": "^8.0.0",
|
|
33
|
+
"typescript": "^5.0.0"
|
|
34
|
+
},
|
|
23
35
|
"keywords": [
|
|
24
36
|
"signskart",
|
|
25
37
|
"upload",
|
|
@@ -29,9 +41,5 @@
|
|
|
29
41
|
"typescript",
|
|
30
42
|
"file-upload",
|
|
31
43
|
"sdk"
|
|
32
|
-
]
|
|
33
|
-
"devDependencies": {
|
|
34
|
-
"tsup": "^8.0.0",
|
|
35
|
-
"typescript": "^5.0.0"
|
|
36
|
-
}
|
|
44
|
+
]
|
|
37
45
|
}
|