@thetechfossil/upfiles 0.3.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.
Files changed (2) hide show
  1. package/README.md +216 -0
  2. package/package.json +2 -3
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thetechfossil/upfiles",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Lightweight client and React components for Upfiles Plugin API (presigned S3)",
5
5
  "license": "MIT",
6
6
  "author": "UpFiles",
@@ -14,8 +14,7 @@
14
14
  "exports": {
15
15
  ".": {
16
16
  "import": "./dist/index.mjs",
17
- "require": "./dist/index.cjs",
18
- "types": "./dist/index.d.ts"
17
+ "require": "./dist/index.cjs"
19
18
  }
20
19
  },
21
20
  "files": [