@igorvaryvoda/sirv-upload-widget 0.1.7 → 0.1.8
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 +20 -106
- package/dist/index.js +7 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7 -14
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,7 +9,6 @@ A React file upload widget for [Sirv CDN](https://sirv.com) with batch uploads,
|
|
|
9
9
|
- **CSV/Excel import** for bulk URL imports
|
|
10
10
|
- **Sirv file picker** to browse existing files
|
|
11
11
|
- **HEIC/HEIF conversion** for iPhone photos
|
|
12
|
-
- **Presigned URL support** for secure direct uploads
|
|
13
12
|
- **Dark mode** with automatic system preference detection
|
|
14
13
|
- **Customizable styling** via CSS variables
|
|
15
14
|
- **TypeScript** support with full type definitions
|
|
@@ -18,52 +17,19 @@ A React file upload widget for [Sirv CDN](https://sirv.com) with batch uploads,
|
|
|
18
17
|
|
|
19
18
|
```bash
|
|
20
19
|
npm install @sirv/upload-widget
|
|
21
|
-
# or
|
|
22
|
-
yarn add @sirv/upload-widget
|
|
23
|
-
# or
|
|
24
|
-
pnpm add @sirv/upload-widget
|
|
25
20
|
```
|
|
26
21
|
|
|
27
22
|
## Quick Start
|
|
28
23
|
|
|
29
|
-
### 1.
|
|
24
|
+
### 1. Deploy the upload proxy
|
|
30
25
|
|
|
31
|
-
The widget uploads
|
|
26
|
+
The widget uploads through a proxy that handles Sirv authentication. Deploy to Cloudflare Workers:
|
|
32
27
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
|
|
37
|
-
|
|
38
|
-
const s3 = new S3Client({
|
|
39
|
-
endpoint: 'https://s3.sirv.com',
|
|
40
|
-
region: 'us-east-1',
|
|
41
|
-
credentials: {
|
|
42
|
-
accessKeyId: process.env.SIRV_S3_KEY!,
|
|
43
|
-
secretAccessKey: process.env.SIRV_S3_SECRET!,
|
|
44
|
-
},
|
|
45
|
-
forcePathStyle: true,
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
export async function POST(req: Request) {
|
|
49
|
-
const { filename, contentType, folder } = await req.json()
|
|
50
|
-
const key = `${folder}/${filename}`.replace(/^\/+/, '')
|
|
51
|
-
|
|
52
|
-
const uploadUrl = await getSignedUrl(s3, new PutObjectCommand({
|
|
53
|
-
Bucket: process.env.SIRV_BUCKET!,
|
|
54
|
-
Key: key,
|
|
55
|
-
ContentType: contentType,
|
|
56
|
-
}), { expiresIn: 300 })
|
|
57
|
-
|
|
58
|
-
return Response.json({
|
|
59
|
-
uploadUrl,
|
|
60
|
-
publicUrl: `https://${process.env.SIRV_BUCKET}.sirv.com/${key}`,
|
|
61
|
-
path: '/' + key,
|
|
62
|
-
})
|
|
63
|
-
}
|
|
64
|
-
```
|
|
28
|
+
[](https://deploy.workers.cloudflare.com/?url=https://github.com/IgorVaryvoda/sirv-uploader/tree/main/examples/cloudflare-worker)
|
|
29
|
+
|
|
30
|
+
You'll need your Sirv API credentials from [Sirv Dashboard → Settings → API](https://my.sirv.com/#/account/settings/api).
|
|
65
31
|
|
|
66
|
-
### 2. Use the widget
|
|
32
|
+
### 2. Use the widget
|
|
67
33
|
|
|
68
34
|
```tsx
|
|
69
35
|
import { SirvUploader } from '@sirv/upload-widget'
|
|
@@ -72,7 +38,7 @@ import '@sirv/upload-widget/styles.css'
|
|
|
72
38
|
export default function UploadPage() {
|
|
73
39
|
return (
|
|
74
40
|
<SirvUploader
|
|
75
|
-
|
|
41
|
+
proxyEndpoint="https://your-worker.workers.dev"
|
|
76
42
|
folder="/uploads"
|
|
77
43
|
onUpload={(files) => {
|
|
78
44
|
console.log('Uploaded files:', files)
|
|
@@ -86,8 +52,7 @@ export default function UploadPage() {
|
|
|
86
52
|
|
|
87
53
|
| Prop | Type | Default | Description |
|
|
88
54
|
|------|------|---------|-------------|
|
|
89
|
-
| `
|
|
90
|
-
| `proxyEndpoint` | `string` | - | Alternative: URL for full proxy mode |
|
|
55
|
+
| `proxyEndpoint` | `string` | - | URL of your upload proxy (Cloudflare Worker) |
|
|
91
56
|
| `folder` | `string` | `"/"` | Default upload folder |
|
|
92
57
|
| `onUpload` | `(files: SirvFile[]) => void` | - | Callback when files are uploaded |
|
|
93
58
|
| `onError` | `(error: string, file?: SirvFile) => void` | - | Callback on upload errors |
|
|
@@ -96,7 +61,6 @@ export default function UploadPage() {
|
|
|
96
61
|
| `maxFileSize` | `number` | `10485760` | Maximum file size in bytes |
|
|
97
62
|
| `autoUpload` | `boolean` | `true` | Start upload immediately on file selection |
|
|
98
63
|
| `concurrency` | `number` | `3` | Number of concurrent uploads |
|
|
99
|
-
| `onConflict` | `'overwrite' \| 'rename' \| 'skip' \| 'ask'` | `'rename'` | Filename conflict handling |
|
|
100
64
|
| `disabled` | `boolean` | `false` | Disable the widget |
|
|
101
65
|
| `compact` | `boolean` | `false` | Compact mode for smaller spaces |
|
|
102
66
|
| `theme` | `'auto' \| 'light' \| 'dark'` | `'auto'` | Color theme (auto follows system preference) |
|
|
@@ -116,7 +80,7 @@ features?: {
|
|
|
116
80
|
|
|
117
81
|
## Dark Mode
|
|
118
82
|
|
|
119
|
-
The widget supports dark mode out of the box
|
|
83
|
+
The widget supports dark mode out of the box:
|
|
120
84
|
|
|
121
85
|
```tsx
|
|
122
86
|
// Auto (default) - follows system preference
|
|
@@ -129,13 +93,9 @@ The widget supports dark mode out of the box with three options:
|
|
|
129
93
|
<SirvUploader theme="dark" ... />
|
|
130
94
|
```
|
|
131
95
|
|
|
132
|
-
Dark mode automatically activates when:
|
|
133
|
-
- `theme="auto"` (default) and the user's system prefers dark mode
|
|
134
|
-
- `theme="dark"` is explicitly set
|
|
135
|
-
|
|
136
96
|
## Styling
|
|
137
97
|
|
|
138
|
-
Customize
|
|
98
|
+
Customize using CSS variables:
|
|
139
99
|
|
|
140
100
|
```css
|
|
141
101
|
.sirv-uploader {
|
|
@@ -145,75 +105,29 @@ Customize the widget using CSS variables:
|
|
|
145
105
|
--sirv-text: #1e293b;
|
|
146
106
|
--sirv-border: #e2e8f0;
|
|
147
107
|
--sirv-radius: 8px;
|
|
148
|
-
/* ... see styles.css for all variables */
|
|
149
108
|
}
|
|
150
109
|
```
|
|
151
110
|
|
|
152
|
-
|
|
111
|
+
## Self-hosting the Proxy
|
|
153
112
|
|
|
154
|
-
|
|
155
|
-
@media (prefers-color-scheme: dark) {
|
|
156
|
-
.sirv-uploader {
|
|
157
|
-
--sirv-primary: #3b82f6;
|
|
158
|
-
--sirv-bg: #1e1e1e;
|
|
159
|
-
--sirv-text: #e5e5e5;
|
|
160
|
-
/* ... */
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
```
|
|
113
|
+
If you prefer to self-host, the proxy is a simple Cloudflare Worker:
|
|
164
114
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
For custom layouts, you can use the components individually:
|
|
168
|
-
|
|
169
|
-
```tsx
|
|
170
|
-
import {
|
|
171
|
-
DropZone,
|
|
172
|
-
FileList,
|
|
173
|
-
FilePicker,
|
|
174
|
-
SpreadsheetImport,
|
|
175
|
-
useSirvUpload,
|
|
176
|
-
} from '@sirv/upload-widget'
|
|
115
|
+
```typescript
|
|
116
|
+
// See examples/cloudflare-worker/src/index.ts
|
|
177
117
|
```
|
|
178
118
|
|
|
119
|
+
Required environment variables:
|
|
120
|
+
- `SIRV_CLIENT_ID` - API Client ID from Sirv
|
|
121
|
+
- `SIRV_CLIENT_SECRET` - API Client Secret from Sirv
|
|
122
|
+
|
|
179
123
|
## TypeScript
|
|
180
124
|
|
|
181
|
-
Full TypeScript support
|
|
125
|
+
Full TypeScript support:
|
|
182
126
|
|
|
183
127
|
```typescript
|
|
184
|
-
import type {
|
|
185
|
-
SirvFile,
|
|
186
|
-
SirvUploaderProps,
|
|
187
|
-
PresignRequest,
|
|
188
|
-
PresignResponse,
|
|
189
|
-
} from '@sirv/upload-widget'
|
|
128
|
+
import type { SirvFile, SirvUploaderProps } from '@sirv/upload-widget'
|
|
190
129
|
```
|
|
191
130
|
|
|
192
|
-
## Backend Examples
|
|
193
|
-
|
|
194
|
-
### Cloudflare Workers (One-Click Deploy)
|
|
195
|
-
|
|
196
|
-
[](https://deploy.workers.cloudflare.com/?url=https://github.com/IgorVaryvoda/sirv-uploader/tree/main/examples/cloudflare-worker)
|
|
197
|
-
|
|
198
|
-
You'll be prompted for your Sirv account name and S3 credentials during deployment.
|
|
199
|
-
|
|
200
|
-
### Other Examples
|
|
201
|
-
|
|
202
|
-
See the `/examples` folder for:
|
|
203
|
-
- `cloudflare-worker/` - Cloudflare Workers (with deploy button)
|
|
204
|
-
- `nextjs-presign.ts` - Next.js API route
|
|
205
|
-
- `express-presign.ts` - Express.js server
|
|
206
|
-
|
|
207
|
-
## How It Works
|
|
208
|
-
|
|
209
|
-
1. User selects files in the widget
|
|
210
|
-
2. Widget requests a presigned URL from your backend
|
|
211
|
-
3. Your backend generates the URL using AWS SDK with Sirv's S3 endpoint
|
|
212
|
-
4. Widget uploads directly to Sirv using the presigned URL
|
|
213
|
-
5. File is available at `https://youraccount.sirv.com/path/to/file.jpg`
|
|
214
|
-
|
|
215
|
-
This approach keeps your Sirv credentials secure on the server while allowing fast, direct uploads from the browser.
|
|
216
|
-
|
|
217
131
|
## License
|
|
218
132
|
|
|
219
133
|
MIT
|
package/dist/index.js
CHANGED
|
@@ -1374,21 +1374,14 @@ function useSirvUpload(options) {
|
|
|
1374
1374
|
if (!proxyEndpoint) throw new Error("No proxy endpoint configured");
|
|
1375
1375
|
if (!file.file) throw new Error("No file data");
|
|
1376
1376
|
updateFile(file.id, { status: "uploading", progress: 10 });
|
|
1377
|
-
const
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
);
|
|
1377
|
+
const uploadUrl = new URL(`${proxyEndpoint}/upload`);
|
|
1378
|
+
uploadUrl.searchParams.set("filename", file.filename);
|
|
1379
|
+
uploadUrl.searchParams.set("folder", folder);
|
|
1381
1380
|
updateFile(file.id, { progress: 30 });
|
|
1382
|
-
const res = await fetch(
|
|
1381
|
+
const res = await fetch(uploadUrl.toString(), {
|
|
1383
1382
|
method: "POST",
|
|
1384
|
-
headers: { "Content-Type":
|
|
1385
|
-
body:
|
|
1386
|
-
data: base64,
|
|
1387
|
-
filename: file.filename,
|
|
1388
|
-
folder,
|
|
1389
|
-
contentType: getMimeType(file.file),
|
|
1390
|
-
onConflict: onConflict === "ask" ? "rename" : onConflict
|
|
1391
|
-
}),
|
|
1383
|
+
headers: { "Content-Type": getMimeType(file.file) },
|
|
1384
|
+
body: file.file,
|
|
1392
1385
|
signal
|
|
1393
1386
|
});
|
|
1394
1387
|
updateFile(file.id, { progress: 80 });
|
|
@@ -1407,7 +1400,7 @@ function useSirvUpload(options) {
|
|
|
1407
1400
|
sirvPath: result.path
|
|
1408
1401
|
});
|
|
1409
1402
|
},
|
|
1410
|
-
[proxyEndpoint, folder,
|
|
1403
|
+
[proxyEndpoint, folder, updateFile]
|
|
1411
1404
|
);
|
|
1412
1405
|
const uploadFile = react.useCallback(
|
|
1413
1406
|
async (id) => {
|