@thetechfossil/upfiles 0.4.0 → 0.5.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 +216 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -196,3 +196,219 @@ export default function PickFile() {
|
|
|
196
196
|
- `POST /api/plugin/upload/presigned-url` – generate presigned S3 URL for upload
|
|
197
197
|
- `GET /api/plugin/thumbnails?fileKey=...` – list thumbnails for a file
|
|
198
198
|
- `GET /api/plugin/files?folderPath=...` – list project files (API key scoped), optional folder prefix
|
|
199
|
+
|
|
200
|
+
## Full API Reference
|
|
201
|
+
|
|
202
|
+
__UpfilesClient(options)__
|
|
203
|
+
|
|
204
|
+
- __options.baseUrl?: string__
|
|
205
|
+
Base origin, for cross-origin Plugin API calls, e.g. `https://upfiles.example.com`. If omitted, requests are same-origin.
|
|
206
|
+
- __options.presignPath?: string__
|
|
207
|
+
Relative path to the presign endpoint (default `/api/plugin/upload/presigned-url`). Used when `presignUrl` is not set.
|
|
208
|
+
- __options.presignUrl?: string__
|
|
209
|
+
Full absolute URL. If provided, it overrides `baseUrl + presignPath`.
|
|
210
|
+
- __options.headers?: Record<string,string>__
|
|
211
|
+
Extra headers to send with every request.
|
|
212
|
+
- __options.withCredentials?: boolean__
|
|
213
|
+
If true, send cookies (useful for session-based routes). Plugin API typically uses API keys instead.
|
|
214
|
+
- __options.apiKey?: string__
|
|
215
|
+
API key value (e.g., `upk_...`).
|
|
216
|
+
- __options.apiKeyHeader?: 'authorization' | 'x-api-key' | 'x-up-api-key'__
|
|
217
|
+
Header to carry the API key. Default `'authorization'`. If set to `'authorization'` and the key starts with `upk_`, `Bearer ${key}` is auto-applied.
|
|
218
|
+
- __options.thumbnailsPath?: string__
|
|
219
|
+
Relative path to thumbnails endpoint, default `/api/plugin/thumbnails`. Used to derive `/api/plugin/files`.
|
|
220
|
+
|
|
221
|
+
Methods
|
|
222
|
+
|
|
223
|
+
- __getPresignedUrl({ fileName, fileType, fileSize, projectId?, folderPath? }): Promise<PresignResponse>__
|
|
224
|
+
Validates inputs and POSTs to the presign endpoint. Returns `{ presignedUrl, fileKey, publicUrl, apiKeyId?, projectId? }`.
|
|
225
|
+
- __uploadToS3(presignedUrl: string, file: File): Promise<Response>__
|
|
226
|
+
Executes the signed PUT request to S3. You are responsible for checking `res.ok`.
|
|
227
|
+
- __upload(file: File, extras?: { projectId?, folderPath?, fetchThumbnails? }): Promise<UploadedFileResult>__
|
|
228
|
+
Convenience method: presign + PUT + optional thumbnails fetch. Returns `{ publicUrl, fileKey, fileName, fileType, fileSize, projectId?, apiKeyId?, thumbnails? }`.
|
|
229
|
+
- __getThumbnails(fileKey: string): Promise<Thumbnail[]>__
|
|
230
|
+
Calls `GET /api/plugin/thumbnails?fileKey=...`.
|
|
231
|
+
- __getProjectFiles({ folderPath? }?): Promise<FileListItem[]>__
|
|
232
|
+
Calls `GET /api/plugin/files?folderPath=...` (derived from `thumbnailsPath`). Returns metadata for each file.
|
|
233
|
+
|
|
234
|
+
Types
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
type PresignResponse = {
|
|
238
|
+
presignedUrl: string;
|
|
239
|
+
fileKey: string;
|
|
240
|
+
publicUrl: string;
|
|
241
|
+
apiKeyId?: string;
|
|
242
|
+
projectId?: string;
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
type UploadedFileResult = {
|
|
246
|
+
publicUrl: string;
|
|
247
|
+
fileKey: string;
|
|
248
|
+
fileName: string;
|
|
249
|
+
fileType: string;
|
|
250
|
+
fileSize: number;
|
|
251
|
+
projectId?: string;
|
|
252
|
+
apiKeyId?: string;
|
|
253
|
+
thumbnails?: Thumbnail[];
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
type Thumbnail = {
|
|
257
|
+
id: string;
|
|
258
|
+
key: string;
|
|
259
|
+
url: string;
|
|
260
|
+
size: number;
|
|
261
|
+
sizeType?: string;
|
|
262
|
+
createdAt?: string;
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
type FileListItem = {
|
|
266
|
+
key: string;
|
|
267
|
+
originalName: string;
|
|
268
|
+
size: number;
|
|
269
|
+
contentType: string;
|
|
270
|
+
uploadedAt: string;
|
|
271
|
+
url: string;
|
|
272
|
+
};
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## React Components
|
|
276
|
+
|
|
277
|
+
__<Uploader />__ from `src/Uploader.tsx`
|
|
278
|
+
|
|
279
|
+
- __clientOptions?: UpfilesClientOptions__
|
|
280
|
+
Supply `baseUrl`, `apiKey`, etc., only if doing cross-origin or custom auth.
|
|
281
|
+
- __multiple?: boolean__ (default: true)
|
|
282
|
+
- __accept?: string[]__
|
|
283
|
+
MIME patterns, default includes common image/video/audio/pdf/text/json.
|
|
284
|
+
- __maxFileSize?: number__ (bytes; default: 100MB)
|
|
285
|
+
- __maxFiles?: number__ (default: 10)
|
|
286
|
+
- __projectId?: string__
|
|
287
|
+
- __folderPath?: string__
|
|
288
|
+
- __fetchThumbnails?: boolean__
|
|
289
|
+
After a successful upload, fetch thumbnails via Plugin API.
|
|
290
|
+
- __onComplete?: (files: UploaderFile[]) => void__
|
|
291
|
+
Called with successful items.
|
|
292
|
+
- __onError?: (error: Error) => void__
|
|
293
|
+
- __className?, buttonClassName?, dropzoneClassName?__
|
|
294
|
+
- __children?__: custom inner content for dropzone.
|
|
295
|
+
|
|
296
|
+
Uploader item shape
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
type UploaderFile = {
|
|
300
|
+
id: string;
|
|
301
|
+
file: File;
|
|
302
|
+
name: string;
|
|
303
|
+
size: number;
|
|
304
|
+
type: string;
|
|
305
|
+
progress: number; // 0-100
|
|
306
|
+
status: 'pending' | 'uploading' | 'success' | 'error';
|
|
307
|
+
error?: string;
|
|
308
|
+
publicUrl?: string;
|
|
309
|
+
fileKey?: string;
|
|
310
|
+
projectId?: string;
|
|
311
|
+
apiKeyId?: string;
|
|
312
|
+
// thumbnails?: Thumbnail[] // added at runtime if fetchThumbnails
|
|
313
|
+
};
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Implementation notes
|
|
317
|
+
|
|
318
|
+
- Uses `XMLHttpRequest` for the S3 PUT to expose upload progress.
|
|
319
|
+
- Progress caps at 99% until completion; then sets to 100% on success.
|
|
320
|
+
- Sets `Content-Type` header to file.type (or `application/octet-stream`).
|
|
321
|
+
|
|
322
|
+
__<ProjectFilesWidget />__ from `src/ProjectFilesWidget.tsx`
|
|
323
|
+
|
|
324
|
+
- __clientOptions: UpfilesClientOptions__
|
|
325
|
+
Provide `baseUrl` and `apiKey` (or `withCredentials`) for Plugin API.
|
|
326
|
+
- __folderPath?: string__
|
|
327
|
+
- __className?, listClassName?, itemClassName?__
|
|
328
|
+
- __onSelect(file): void__
|
|
329
|
+
Receives `{ name, key, url, size, contentType }`.
|
|
330
|
+
- __saveUrl?: string__
|
|
331
|
+
If set, the component will POST the selected file JSON to this URL (same-origin).
|
|
332
|
+
- __onSave?: (file) => Promise<void> | void__
|
|
333
|
+
- __onSaved?: (result?: any) => void__
|
|
334
|
+
|
|
335
|
+
Behavior
|
|
336
|
+
|
|
337
|
+
- Loads files via `client.getProjectFiles({ folderPath })` on mount and when refreshed.
|
|
338
|
+
- Client-side search by filename.
|
|
339
|
+
- Built-in "Use" action triggers `onSelect`, optional `onSave` and/or POST to `saveUrl`.
|
|
340
|
+
|
|
341
|
+
## Configuration and Auth
|
|
342
|
+
|
|
343
|
+
- __Same-origin__ usage needs no config. Ensure your app exposes the Plugin API routes documented above.
|
|
344
|
+
- __Cross-origin plugins__ should:
|
|
345
|
+
- Set `baseUrl` to your Upfiles app origin.
|
|
346
|
+
- Provide `apiKey` and set `apiKeyHeader` as needed. If using `'authorization'` and key starts with `upk_`, `Bearer` is added automatically.
|
|
347
|
+
- Configure CORS on the Upfiles app to allow your plugin origin.
|
|
348
|
+
- __Cookies with NextAuth or session routes__:
|
|
349
|
+
- Set `withCredentials: true` in `UpfilesClient` and allow credentials server-side. Plugin API is usually API-key based instead.
|
|
350
|
+
|
|
351
|
+
## Error Handling
|
|
352
|
+
|
|
353
|
+
- Network/API errors in `getPresignedUrl`, `getThumbnails`, `getProjectFiles` throw with a friendly message when possible.
|
|
354
|
+
- In `<Uploader />`, per-file errors are surfaced via item `error` and `status: 'error'`, and the component continues uploading other files.
|
|
355
|
+
- `uploadToS3` returns a Response; check `res.ok`. The convenience `upload()` will throw if the PUT fails.
|
|
356
|
+
|
|
357
|
+
## Troubleshooting
|
|
358
|
+
|
|
359
|
+
- __`Failed to get upload URL`__
|
|
360
|
+
- Check your presign route is reachable (correct `baseUrl`/`presignUrl`).
|
|
361
|
+
- Ensure `fileSize` is provided and > 0.
|
|
362
|
+
- Verify API key header and value; confirm CORS on the server.
|
|
363
|
+
- __S3 PUT 403/SignatureDoesNotMatch__
|
|
364
|
+
- Do not modify headers other than `Content-Type`.
|
|
365
|
+
- Ensure the file name/type/size used for presign match the actual uploaded file.
|
|
366
|
+
- __CORS errors__
|
|
367
|
+
- Allow your plugin origin on the Upfiles app for Plugin API paths and S3 bucket CORS for PUT/GET.
|
|
368
|
+
- __Large files stall at 99%__
|
|
369
|
+
- Expected: progress caps at 99% until PUT resolves, then jumps to 100%.
|
|
370
|
+
- __No files listed in ProjectFilesWidget__
|
|
371
|
+
- Confirm the API key belongs to a project with files.
|
|
372
|
+
- Ensure `thumbnailsPath` is correct so `/files` is derived properly.
|
|
373
|
+
|
|
374
|
+
## FAQ
|
|
375
|
+
|
|
376
|
+
- __Can I use it without React?__ Yes—use `UpfilesClient` directly (see vanilla example).
|
|
377
|
+
- __How do I restrict uploads to a folder?__ Provide `folderPath` when presigning (`<Uploader folderPath="my-plugin/" />` or `client.upload(..., { folderPath })`).
|
|
378
|
+
- __How do I associate uploads with a project?__ Provide `projectId` when presigning or via `client.upload(..., { projectId })`.
|
|
379
|
+
- __Can I customize headers?__ Pass `headers` in `UpfilesClientOptions`.
|
|
380
|
+
|
|
381
|
+
## Example: Minimal cross-origin plugin
|
|
382
|
+
|
|
383
|
+
```tsx
|
|
384
|
+
import { Uploader } from '@thetechfossil/upfiles';
|
|
385
|
+
|
|
386
|
+
export default function Widget() {
|
|
387
|
+
return (
|
|
388
|
+
<Uploader
|
|
389
|
+
clientOptions={{
|
|
390
|
+
baseUrl: 'https://upfiles.example.com',
|
|
391
|
+
apiKey: process.env.NEXT_PUBLIC_UPFILES_API_KEY!,
|
|
392
|
+
apiKeyHeader: 'authorization',
|
|
393
|
+
}}
|
|
394
|
+
multiple
|
|
395
|
+
accept={['image/*']}
|
|
396
|
+
maxFileSize={20 * 1024 * 1024}
|
|
397
|
+
folderPath="my-plugin/"
|
|
398
|
+
fetchThumbnails
|
|
399
|
+
onComplete={(files) => console.log('Uploaded', files)}
|
|
400
|
+
onError={(e) => console.error(e)}
|
|
401
|
+
/>
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
## Development
|
|
407
|
+
|
|
408
|
+
- Build: `bun run build`
|
|
409
|
+
- Watch: `bun run dev`
|
|
410
|
+
- Typecheck: `bun run typecheck`
|
|
411
|
+
|
|
412
|
+
## License
|
|
413
|
+
|
|
414
|
+
MIT UpFiles
|