@vivinkv28/strapi-provider-uploadthing 0.1.3 → 0.1.5
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 +130 -34
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
# @vivinkv28/strapi-provider-uploadthing
|
|
2
2
|
|
|
3
|
-
UploadThing provider for the Strapi
|
|
3
|
+
UploadThing provider for the Strapi Uploads
|
|
4
4
|
|
|
5
|
-
This
|
|
5
|
+
This provider stores Strapi Media Library files in UploadThing while keeping file records and metadata inside Strapi.
|
|
6
6
|
|
|
7
|
-
## What
|
|
7
|
+
## What This Provider Does
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
- Uploads Strapi media files to UploadThing
|
|
10
|
+
- Stores UploadThing metadata in `provider_metadata.uploadthing`
|
|
11
|
+
- Uses the UploadThing file URL as the Strapi file URL
|
|
12
|
+
- Supports both `upload` and `uploadStream`
|
|
13
|
+
- Supports signed URLs for private files
|
|
14
|
+
- Deletes the remote file when the Strapi file is deleted
|
|
15
|
+
- Uses predictable `customId` values by default
|
|
16
|
+
- Retries transient upload failures automatically
|
|
17
|
+
- Handles replace-media conflicts more safely
|
|
10
18
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
## Features
|
|
19
|
+
## Requirements
|
|
14
20
|
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
- Use UploadThing `ufsUrl` as the Strapi asset URL
|
|
18
|
-
- Support `upload` and `uploadStream`
|
|
19
|
-
- Support private files with signed URL generation
|
|
20
|
-
- Delete remote files when media is removed from Strapi
|
|
21
|
-
- Keep predictable custom IDs by default
|
|
22
|
-
- Retry transient UploadThing ingest failures automatically
|
|
23
|
-
- Improve replace-media reliability with conflict fallback handling
|
|
21
|
+
- Node.js `>= 20.0.0`
|
|
22
|
+
- Strapi v5
|
|
24
23
|
|
|
25
24
|
## Installation
|
|
26
25
|
|
|
@@ -30,20 +29,22 @@ Install the provider in your Strapi project:
|
|
|
30
29
|
npm install @vivinkv28/strapi-provider-uploadthing
|
|
31
30
|
```
|
|
32
31
|
|
|
33
|
-
##
|
|
32
|
+
## Quick Start
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
1. Add your UploadThing token to `.env`.
|
|
35
|
+
2. Configure the upload provider in `config/plugins.ts`.
|
|
36
|
+
3. Update `config/middlewares.ts` so Strapi allows UploadThing media URLs in the admin.
|
|
37
|
+
4. Restart Strapi.
|
|
37
38
|
|
|
38
39
|
## Environment Variables
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
Minimum required:
|
|
41
42
|
|
|
42
43
|
```env
|
|
43
44
|
UPLOADTHING_TOKEN=your_uploadthing_token
|
|
44
45
|
```
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
Typical public-file setup:
|
|
47
48
|
|
|
48
49
|
```env
|
|
49
50
|
UPLOADTHING_TOKEN=your_uploadthing_token
|
|
@@ -57,6 +58,15 @@ UPLOADTHING_USE_CUSTOM_ID=true
|
|
|
57
58
|
UPLOADTHING_LOG_LEVEL=Info
|
|
58
59
|
```
|
|
59
60
|
|
|
61
|
+
Typical private-file setup:
|
|
62
|
+
|
|
63
|
+
```env
|
|
64
|
+
UPLOADTHING_TOKEN=your_uploadthing_token
|
|
65
|
+
UPLOADTHING_ACL=private
|
|
66
|
+
UPLOADTHING_PRIVATE_FILES=true
|
|
67
|
+
UPLOADTHING_SIGNED_URL_EXPIRES_IN=3600
|
|
68
|
+
```
|
|
69
|
+
|
|
60
70
|
## Strapi Configuration
|
|
61
71
|
|
|
62
72
|
Create or update `./config/plugins.ts`:
|
|
@@ -87,31 +97,117 @@ export default ({ env }) => ({
|
|
|
87
97
|
});
|
|
88
98
|
```
|
|
89
99
|
|
|
100
|
+
Update `./config/middlewares.ts` as well. This step is required so Strapi's Content Security Policy allows UploadThing-hosted images and media to load in the admin panel and Media Library:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import type { Core } from '@strapi/strapi';
|
|
104
|
+
|
|
105
|
+
const config: Core.Config.Middlewares = [
|
|
106
|
+
'strapi::logger',
|
|
107
|
+
'strapi::errors',
|
|
108
|
+
{
|
|
109
|
+
name: 'strapi::security',
|
|
110
|
+
config: {
|
|
111
|
+
contentSecurityPolicy: {
|
|
112
|
+
useDefaults: true,
|
|
113
|
+
directives: {
|
|
114
|
+
'connect-src': ["'self'", 'https:'],
|
|
115
|
+
'img-src': ["'self'", 'data:', 'blob:', 'https://*.ufs.sh', 'https://utfs.io'],
|
|
116
|
+
'media-src': ["'self'", 'data:', 'blob:', 'https://*.ufs.sh', 'https://utfs.io'],
|
|
117
|
+
upgradeInsecureRequests: null,
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
'strapi::cors',
|
|
123
|
+
'strapi::poweredBy',
|
|
124
|
+
'strapi::query',
|
|
125
|
+
'strapi::body',
|
|
126
|
+
'strapi::session',
|
|
127
|
+
'strapi::favicon',
|
|
128
|
+
'strapi::public',
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
export default config;
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
If you already have a `strapi::security` middleware entry, merge these UploadThing domains into your existing CSP directives instead of adding a second `strapi::security` entry.
|
|
135
|
+
|
|
136
|
+
## Public vs Private Files
|
|
137
|
+
|
|
138
|
+
This is the part most people get confused by:
|
|
139
|
+
|
|
140
|
+
- `acl` controls how the file is stored in UploadThing.
|
|
141
|
+
- `privateFiles` controls how Strapi serves the file.
|
|
142
|
+
|
|
143
|
+
Use this combination for public files:
|
|
144
|
+
|
|
145
|
+
```env
|
|
146
|
+
UPLOADTHING_ACL=public-read
|
|
147
|
+
UPLOADTHING_PRIVATE_FILES=false
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Use this combination for private files:
|
|
151
|
+
|
|
152
|
+
```env
|
|
153
|
+
UPLOADTHING_ACL=private
|
|
154
|
+
UPLOADTHING_PRIVATE_FILES=true
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
If you set only `privateFiles=true`, Strapi will generate signed URLs, but the uploaded file may still be stored with a public ACL depending on your UploadThing configuration.
|
|
158
|
+
|
|
159
|
+
## How Private Files Work
|
|
160
|
+
|
|
161
|
+
When `privateFiles` is enabled:
|
|
162
|
+
|
|
163
|
+
1. The provider tells Strapi that files should be treated as private.
|
|
164
|
+
2. Strapi asks the provider for a signed URL whenever it needs to serve the file.
|
|
165
|
+
3. The provider requests a temporary signed URL from UploadThing using the stored `customId` or `fileKey`.
|
|
166
|
+
4. Strapi returns that temporary URL to the client.
|
|
167
|
+
|
|
168
|
+
The signed URL lifetime is controlled by `signedUrlExpiresIn`.
|
|
169
|
+
|
|
90
170
|
## Provider Options
|
|
91
171
|
|
|
92
172
|
| Option | Type | Default | Description |
|
|
93
173
|
| --- | --- | --- | --- |
|
|
94
174
|
| `token` | `string` | `process.env.UPLOADTHING_TOKEN` | UploadThing token used to initialize `UTApi`. |
|
|
95
|
-
| `acl` | `
|
|
96
|
-
| `privateFiles` | `boolean` | `false` |
|
|
97
|
-
| `contentDisposition` | `
|
|
98
|
-
| `signedUrlExpiresIn` | `number` | `3600` | Signed URL
|
|
99
|
-
| `uploadConcurrency` | `number` | `1` | Maximum concurrent uploads handled by the provider. Values above `25` are capped
|
|
175
|
+
| `acl` | `'public-read' \| 'private'` | `undefined` | ACL passed to UploadThing during upload. Use `'public-read'` for public files or `'private'` for storage-level private files. |
|
|
176
|
+
| `privateFiles` | `boolean` | `false` | Tells Strapi to treat files as private and request signed URLs when serving them. |
|
|
177
|
+
| `contentDisposition` | `'inline' \| 'attachment'` | `'inline'` | Content disposition sent to UploadThing during upload. |
|
|
178
|
+
| `signedUrlExpiresIn` | `number` | `3600` | Signed URL lifetime in seconds. Used when Strapi requests a private file URL. |
|
|
179
|
+
| `uploadConcurrency` | `number` | `1` | Maximum number of concurrent uploads handled by the provider. Values above `25` are capped to `25`. |
|
|
100
180
|
| `uploadRetries` | `number` | `2` | Number of retry attempts for transient UploadThing upload failures. |
|
|
101
|
-
| `useCustomId` | `boolean` | `true` | Uses a deterministic UploadThing `customId` based on Strapi file hash and extension. |
|
|
181
|
+
| `useCustomId` | `boolean` | `true` | Uses a deterministic UploadThing `customId` based on the Strapi file hash and extension. |
|
|
102
182
|
| `apiUrl` | `string` | `undefined` | Optional custom UploadThing API URL. |
|
|
103
183
|
| `ingestUrl` | `string` | `undefined` | Optional custom UploadThing ingest URL. |
|
|
104
184
|
| `logLevel` | `string` | `undefined` | Optional UploadThing log level. |
|
|
105
185
|
| `logFormat` | `string` | `undefined` | Optional UploadThing log format. |
|
|
106
186
|
| `isDev` | `boolean` | `undefined` | Optional UploadThing development mode flag. |
|
|
107
187
|
|
|
108
|
-
##
|
|
109
|
-
|
|
110
|
-
If `privateFiles` is enabled, the provider reports files as private and asks UploadThing for a signed URL when Strapi serves them.
|
|
188
|
+
## Stored Metadata
|
|
111
189
|
|
|
112
|
-
|
|
190
|
+
After upload, this provider stores UploadThing-specific metadata in:
|
|
113
191
|
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
UPLOADTHING_SIGNED_URL_EXPIRES_IN=3600
|
|
192
|
+
```txt
|
|
193
|
+
provider_metadata.uploadthing
|
|
117
194
|
```
|
|
195
|
+
|
|
196
|
+
That metadata includes values such as:
|
|
197
|
+
|
|
198
|
+
- `fileKey`
|
|
199
|
+
- `customId`
|
|
200
|
+
- `url`
|
|
201
|
+
- `ufsUrl`
|
|
202
|
+
- `name`
|
|
203
|
+
- `size`
|
|
204
|
+
|
|
205
|
+
## Notes
|
|
206
|
+
|
|
207
|
+
- The provider uses UploadThing `ufsUrl` as the file URL stored in Strapi.
|
|
208
|
+
- If `useCustomId` is enabled, the provider prefers `customId` when generating signed URLs or deleting files.
|
|
209
|
+
- If a deterministic `customId` conflicts during replace-media flows, the provider falls back to a unique ID and retries the upload.
|
|
210
|
+
|
|
211
|
+
## Learn More
|
|
212
|
+
|
|
213
|
+
- [UploadThing](https://uploadthing.com/)
|