@uploadista/vue 0.0.3

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 ADDED
@@ -0,0 +1,554 @@
1
+ # @uploadista/vue
2
+
3
+ Vue 3 client for Uploadista - file uploads and flow management with Vue Composition API.
4
+
5
+ ## Features
6
+
7
+ - Vue 3 Composition API composables for file uploads
8
+ - Flow-based upload processing
9
+ - WebSocket support for real-time progress
10
+ - TypeScript support
11
+ - Reactive state management
12
+ - Drag and drop support
13
+ - Multiple concurrent uploads
14
+ - Upload metrics and monitoring
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ pnpm add @uploadista/vue
20
+ # or
21
+ npm install @uploadista/vue
22
+ # or
23
+ yarn add @uploadista/vue
24
+ ```
25
+
26
+ ## Requirements
27
+
28
+ - Vue 3.3 or higher
29
+ - TypeScript 5.0+ (optional but recommended)
30
+
31
+ ## Quick Start
32
+
33
+ ### 1. Install the Plugin
34
+
35
+ ```typescript
36
+ // main.ts
37
+ import { createApp } from 'vue'
38
+ import { createUploadistaPlugin } from '@uploadista/vue'
39
+ import App from './App.vue'
40
+
41
+ const app = createApp(App)
42
+
43
+ app.use(createUploadistaPlugin({
44
+ serverUrl: 'http://localhost:4200', // Your Uploadista server URL
45
+ auth: {
46
+ type: 'saas',
47
+ apiKey: 'your-api-key'
48
+ }
49
+ }))
50
+
51
+ app.mount('#app')
52
+ ```
53
+
54
+ ### 2. Use Composables in Components
55
+
56
+ ```vue
57
+ <script setup lang="ts">
58
+ import { useUpload } from '@uploadista/vue'
59
+
60
+ const { state, upload, abort, reset } = useUpload()
61
+
62
+ const handleFileChange = async (event: Event) => {
63
+ const file = (event.target as HTMLInputElement).files?.[0]
64
+ if (file) {
65
+ await upload(file)
66
+ }
67
+ }
68
+ </script>
69
+
70
+ <template>
71
+ <div>
72
+ <input type="file" @change="handleFileChange" :disabled="state.status === 'uploading'" />
73
+
74
+ <div v-if="state.status === 'uploading'">
75
+ <p>Progress: {{ state.progress.toFixed(0) }}%</p>
76
+ <button @click="abort">Cancel</button>
77
+ </div>
78
+
79
+ <div v-if="state.status === 'success'">
80
+ <p>Upload complete!</p>
81
+ <p>File ID: {{ state.result?.fileId }}</p>
82
+ </div>
83
+
84
+ <div v-if="state.status === 'error'">
85
+ <p>Error: {{ state.error?.message }}</p>
86
+ <button @click="reset">Try Again</button>
87
+ </div>
88
+ </div>
89
+ </template>
90
+ ```
91
+
92
+ ## API Reference
93
+
94
+ ### Plugin
95
+
96
+ #### `createUploadistaPlugin(options)`
97
+
98
+ Creates the Uploadista Vue plugin.
99
+
100
+ **Options:**
101
+ - `serverUrl` - Uploadista server URL
102
+ - `auth` - Authentication configuration
103
+ - `type: 'no-auth' | 'saas' | 'direct'`
104
+ - For SaaS: `{ type: 'saas', apiKey: string, projectId?: string }`
105
+ - For direct: `{ type: 'direct', getAuthorizationHeader: () => Promise<string> }`
106
+
107
+ ### Composables
108
+
109
+ #### `useUploadistaClient()`
110
+
111
+ Access the Uploadista client instance.
112
+
113
+ ```typescript
114
+ const client = useUploadistaClient()
115
+ ```
116
+
117
+ #### `useUpload(options?)`
118
+
119
+ Single file upload with progress tracking.
120
+
121
+ **Returns:**
122
+ - `state` - Reactive upload state (readonly)
123
+ - `status` - Upload status: 'idle' | 'uploading' | 'success' | 'error' | 'aborted'
124
+ - `progress` - Progress percentage (0-100)
125
+ - `bytesUploaded` - Bytes uploaded
126
+ - `totalBytes` - Total file size
127
+ - `result` - Upload result (when successful)
128
+ - `error` - Error object (when failed)
129
+ - `upload(file, options?)` - Start upload
130
+ - `abort()` - Cancel upload
131
+ - `reset()` - Reset to initial state
132
+ - `retry()` - Retry failed upload
133
+
134
+ **Options:**
135
+ - `onProgress` - Progress callback
136
+ - `onComplete` - Completion callback
137
+ - `onError` - Error callback
138
+
139
+ #### `useMultiUpload(options?)`
140
+
141
+ Multiple file uploads with aggregate tracking.
142
+
143
+ **Returns:**
144
+ - `uploads` - Array of upload items (readonly)
145
+ - `stats` - Aggregate statistics (readonly)
146
+ - `totalFiles`, `completedFiles`, `failedFiles`
147
+ - `totalBytes`, `uploadedBytes`
148
+ - `totalProgress`, `allComplete`, `hasErrors`
149
+ - `add(files)` - Add files to upload queue
150
+ - `remove(uploadId)` - Remove upload
151
+ - `clear()` - Clear all uploads
152
+ - `retryFailed()` - Retry all failed uploads
153
+
154
+ #### `useFlowUpload(options?)`
155
+
156
+ Upload file through a flow pipeline.
157
+
158
+ **Returns:**
159
+ - `state` - Reactive flow upload state (readonly)
160
+ - Includes all `useUpload` state
161
+ - `jobId` - Flow job ID
162
+ - `flowStatus` - Flow status
163
+ - `flowResult` - Flow result
164
+ - `uploadFlow(file, flowOptions)` - Start flow upload
165
+ - `abort()` - Cancel flow upload
166
+ - `reset()` - Reset state
167
+
168
+ #### `useMultiFlowUpload(options?)`
169
+
170
+ Multiple flow uploads with aggregate tracking.
171
+
172
+ Similar to `useMultiUpload` but for flow uploads.
173
+
174
+ #### `useDragDrop(options?)`
175
+
176
+ Drag and drop file handling.
177
+
178
+ **Returns:**
179
+ - `isDragging` - Drag in progress (readonly)
180
+ - `isOver` - Dragging over drop zone (readonly)
181
+ - `files` - Dropped files (readonly)
182
+ - `onDragEnter` - Handler for drag enter event
183
+ - `onDragLeave` - Handler for drag leave event
184
+ - `onDragOver` - Handler for drag over event
185
+ - `onDrop` - Handler for drop event
186
+ - `clearFiles` - Clear dropped files
187
+
188
+ **Options:**
189
+ - `accept` - Accepted file types
190
+ - `maxSize` - Maximum file size in bytes
191
+ - `multiple` - Allow multiple files (default: true)
192
+ - `onFilesDropped` - Callback when files are dropped
193
+
194
+ #### `useFlow(flowId, options?)`
195
+
196
+ Execute a flow.
197
+
198
+ **Returns:**
199
+ - `state` - Flow execution state (readonly)
200
+ - `execute(input)` - Execute flow
201
+ - `cancel()` - Cancel flow execution
202
+
203
+ #### `useFlowClient()`
204
+
205
+ Access the flow client.
206
+
207
+ ```typescript
208
+ const flowClient = useFlowClient()
209
+ ```
210
+
211
+ #### `useFlowWebSocket(jobId)`
212
+
213
+ Manage flow WebSocket connection.
214
+
215
+ **Returns:**
216
+ - `isConnected` - Connection status (readonly)
217
+ - `events` - Flow events stream (readonly)
218
+ - `connect()` - Connect to WebSocket
219
+ - `disconnect()` - Disconnect WebSocket
220
+ - `sendPing()` - Send ping message
221
+
222
+ #### `useUploadMetrics()`
223
+
224
+ Access upload performance metrics.
225
+
226
+ **Returns:**
227
+ - `metrics` - Upload metrics (readonly)
228
+ - Network speed, chunk timing, etc.
229
+
230
+ ### Components
231
+
232
+ #### `<UploadZone>`
233
+
234
+ File input with drag and drop zone.
235
+
236
+ **Props:**
237
+ - `accept` - Accepted file types
238
+ - `multiple` - Allow multiple files
239
+ - `disabled` - Disable input
240
+
241
+ **Events:**
242
+ - `@file-select` - Emitted when files are selected
243
+
244
+ **Slots:**
245
+ - `default` - Custom drop zone content
246
+
247
+ #### `<UploadList>`
248
+
249
+ Display upload progress for multiple files.
250
+
251
+ **Props:**
252
+ - `uploads` - Array of upload items
253
+
254
+ **Slots:**
255
+ - `item` - Custom upload item template
256
+
257
+ #### `<FlowUploadZone>`
258
+
259
+ Upload zone with flow configuration.
260
+
261
+ **Props:**
262
+ - `flowId` - Flow ID
263
+ - `accept` - Accepted file types
264
+ - `multiple` - Allow multiple files
265
+
266
+ **Events:**
267
+ - `@upload-complete` - Emitted when upload completes
268
+
269
+ #### `<FlowUploadList>`
270
+
271
+ Display flow upload progress.
272
+
273
+ **Props:**
274
+ - `uploads` - Array of flow upload items
275
+
276
+ **Slots:**
277
+ - `item` - Custom upload item template
278
+
279
+ ### Utilities
280
+
281
+ ```typescript
282
+ import {
283
+ formatFileSize,
284
+ formatProgress,
285
+ isImageFile,
286
+ isVideoFile,
287
+ createFileSizeValidator,
288
+ createFileTypeValidator,
289
+ composeValidators
290
+ } from '@uploadista/vue/utils'
291
+ ```
292
+
293
+ See [framework-utils documentation](../../client/src/framework-utils.ts) for details.
294
+
295
+ ## Examples
296
+
297
+ ### Example: Multiple File Upload with Progress
298
+
299
+ ```vue
300
+ <script setup lang="ts">
301
+ import { useMultiUpload } from '@uploadista/vue'
302
+
303
+ const { uploads, stats, add, clear, retryFailed } = useMultiUpload()
304
+
305
+ const handleFilesSelected = async (files: File[]) => {
306
+ await add(files)
307
+ }
308
+ </script>
309
+
310
+ <template>
311
+ <div>
312
+ <input
313
+ type="file"
314
+ multiple
315
+ @change="handleFilesSelected(($event.target as HTMLInputElement).files || [])"
316
+ />
317
+
318
+ <div v-if="stats.totalFiles > 0">
319
+ <p>Progress: {{ stats.totalProgress.toFixed(0) }}%</p>
320
+ <p>
321
+ Uploaded: {{ stats.completedFiles }}/{{ stats.totalFiles }}
322
+ ({{ (stats.uploadedBytes / 1024 / 1024).toFixed(2) }}MB / {{ (stats.totalBytes / 1024 / 1024).toFixed(2) }}MB)
323
+ </p>
324
+
325
+ <div v-for="upload of uploads" :key="upload.id" class="upload-item">
326
+ <span>{{ upload.filename }}</span>
327
+ <progress :value="upload.progress" max="100"></progress>
328
+ <span>{{ upload.status }}</span>
329
+ </div>
330
+
331
+ <button @click="clear" :disabled="!stats.allComplete">Clear All</button>
332
+ <button v-if="stats.hasErrors" @click="retryFailed">Retry Failed</button>
333
+ </div>
334
+ </div>
335
+ </template>
336
+ ```
337
+
338
+ ### Example: Flow-based Upload with Processing
339
+
340
+ ```vue
341
+ <script setup lang="ts">
342
+ import { useFlowUpload } from '@uploadista/vue'
343
+
344
+ const { state, uploadFlow, abort, reset } = useFlowUpload()
345
+
346
+ const handleFlowUpload = async (file: File) => {
347
+ // Upload file through a flow pipeline (e.g., image resize, optimization)
348
+ await uploadFlow(file, {
349
+ flowId: 'image-processor',
350
+ onProgress: (event) => console.log('Processing:', event)
351
+ })
352
+ }
353
+ </script>
354
+
355
+ <template>
356
+ <div>
357
+ <input type="file" @change="(e) => handleFlowUpload((e.target as HTMLInputElement).files?.[0]!)" />
358
+
359
+ <div v-if="state.status === 'uploading'">
360
+ <p>Upload Progress: {{ state.progress.toFixed(0) }}%</p>
361
+ <p>Flow Status: {{ state.flowStatus }}</p>
362
+ <button @click="abort">Cancel</button>
363
+ </div>
364
+
365
+ <div v-if="state.status === 'success'">
366
+ <p>Processing Complete!</p>
367
+ <p v-if="state.flowResult">Result: {{ JSON.stringify(state.flowResult) }}</p>
368
+ <button @click="reset">Upload Another</button>
369
+ </div>
370
+ </div>
371
+ </template>
372
+ ```
373
+
374
+ ### Example: Drag and Drop Upload
375
+
376
+ ```vue
377
+ <script setup lang="ts">
378
+ import { useUpload, useDragDrop } from '@uploadista/vue'
379
+
380
+ const { state, upload } = useUpload()
381
+ const { isDragging, isOver, onDragEnter, onDragLeave, onDragOver, onDrop } = useDragDrop({
382
+ accept: ['image/*', 'application/pdf'],
383
+ maxSize: 10 * 1024 * 1024, // 10MB
384
+ onFilesDropped: async (files) => {
385
+ if (files.length > 0) {
386
+ await upload(files[0])
387
+ }
388
+ }
389
+ })
390
+ </script>
391
+
392
+ <template>
393
+ <div
394
+ @dragenter="onDragEnter"
395
+ @dragleave="onDragLeave"
396
+ @dragover="onDragOver"
397
+ @drop="onDrop"
398
+ :class="{ dragging: isDragging, over: isOver }"
399
+ class="drop-zone"
400
+ >
401
+ <p v-if="!isDragging">Drag files here or click to select</p>
402
+ <p v-else>Drop files to upload</p>
403
+
404
+ <input type="file" hidden accept="image/*,application/pdf" />
405
+
406
+ <div v-if="state.status === 'uploading'">
407
+ <progress :value="state.progress" max="100"></progress>
408
+ </div>
409
+ </div>
410
+ </template>
411
+
412
+ <style scoped>
413
+ .drop-zone {
414
+ border: 2px dashed #ccc;
415
+ padding: 2rem;
416
+ border-radius: 8px;
417
+ text-align: center;
418
+ cursor: pointer;
419
+ }
420
+
421
+ .drop-zone.dragging {
422
+ background-color: #f0f0f0;
423
+ }
424
+
425
+ .drop-zone.over {
426
+ border-color: #007bff;
427
+ background-color: #e7f3ff;
428
+ }
429
+ </style>
430
+ ```
431
+
432
+ ### Example: Using `UploadZone` Component
433
+
434
+ ```vue
435
+ <script setup lang="ts">
436
+ import { UploadZone, UploadList } from '@uploadista/vue'
437
+ import { useMultiUpload } from '@uploadista/vue'
438
+
439
+ const { uploads, add } = useMultiUpload()
440
+
441
+ const handleFileSelect = async (files: File[]) => {
442
+ await add(files)
443
+ }
444
+ </script>
445
+
446
+ <template>
447
+ <div>
448
+ <UploadZone
449
+ multiple
450
+ accept="image/*"
451
+ @file-select="handleFileSelect"
452
+ >
453
+ <div class="custom-drop-zone">
454
+ <p>Drop images here or click to browse</p>
455
+ </div>
456
+ </UploadZone>
457
+
458
+ <UploadList :uploads="uploads">
459
+ <template #item="{ upload }">
460
+ <div class="upload-item">
461
+ <span>{{ upload.filename }}</span>
462
+ <progress :value="upload.progress" max="100"></progress>
463
+ <span class="status">{{ upload.status }}</span>
464
+ </div>
465
+ </template>
466
+ </UploadList>
467
+ </div>
468
+ </template>
469
+
470
+ <style scoped>
471
+ .custom-drop-zone {
472
+ padding: 2rem;
473
+ border: 2px dashed #ccc;
474
+ border-radius: 8px;
475
+ text-align: center;
476
+ }
477
+
478
+ .upload-item {
479
+ display: flex;
480
+ align-items: center;
481
+ gap: 1rem;
482
+ padding: 1rem;
483
+ border-bottom: 1px solid #eee;
484
+ }
485
+
486
+ .status {
487
+ margin-left: auto;
488
+ font-size: 0.875rem;
489
+ color: #666;
490
+ }
491
+ </style>
492
+ ```
493
+
494
+ See the [Vue example application](../../../../examples/vue-client/) for comprehensive usage examples:
495
+
496
+ - Basic single upload
497
+ - Multiple file uploads
498
+ - Flow-based processing
499
+ - Drag and drop
500
+ - Custom styling
501
+ - Error handling
502
+ - Retry logic
503
+
504
+ ## TypeScript Support
505
+
506
+ This package includes full TypeScript types. No additional `@types` package is needed.
507
+
508
+ ```typescript
509
+ import type {
510
+ UploadState,
511
+ FlowUploadState,
512
+ UseUploadOptions,
513
+ UseFlowUploadOptions
514
+ } from '@uploadista/vue'
515
+ ```
516
+
517
+ ## SSR Considerations
518
+
519
+ The Vue client works with Nuxt.js and other SSR frameworks. The client is initialized on the client side only:
520
+
521
+ ```typescript
522
+ // plugins/uploadista.client.ts (Nuxt)
523
+ export default defineNuxtPlugin((nuxtApp) => {
524
+ const uploadista = createUploadistaPlugin({
525
+ serverUrl: useRuntimeConfig().public.uploadistaUrl,
526
+ auth: { type: 'no-auth' }
527
+ })
528
+
529
+ nuxtApp.vueApp.use(uploadista)
530
+ })
531
+ ```
532
+
533
+ ## Migration from React
534
+
535
+ If you're familiar with the React client, here's a quick mapping:
536
+
537
+ | React | Vue |
538
+ |-------|-----|
539
+ | `useState` | `ref` / `reactive` |
540
+ | `useEffect` | `watch` / `watchEffect` / `onMounted` / `onUnmounted` |
541
+ | `useCallback` | Not needed (functions are stable in Vue composables) |
542
+ | `useMemo` | `computed` |
543
+ | `useContext` | `provide` / `inject` |
544
+ | `<UploadistaProvider>` | `app.use(createUploadistaPlugin())` |
545
+
546
+ All hooks have equivalent composables with the same names (e.g., `useUpload`, `useMultiUpload`).
547
+
548
+ ## Contributing
549
+
550
+ See the main [Uploadista documentation](../../../../README.md) for contribution guidelines.
551
+
552
+ ## License
553
+
554
+ MIT
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@uploadista/vue",
3
+ "type": "module",
4
+ "version": "0.0.3",
5
+ "description": "Vue client for Uploadista",
6
+ "license": "MIT",
7
+ "author": "Uploadista",
8
+ "exports": {
9
+ ".": "./src/index.ts",
10
+ "./composables/*": "./src/composables/*.ts",
11
+ "./components/*": "./src/components/*.vue",
12
+ "./providers/*": "./src/providers/*.vue",
13
+ "./utils/*": "./src/utils/*.ts"
14
+ },
15
+ "peerDependencies": {
16
+ "vue": "^3.3.0"
17
+ },
18
+ "dependencies": {
19
+ "@uploadista/core": "0.0.3",
20
+ "@uploadista/client-browser": "0.0.3"
21
+ },
22
+ "devDependencies": {
23
+ "@vue/test-utils": "^2.4.6",
24
+ "vitest": "3.2.4",
25
+ "vue": "^3.5.0",
26
+ "@uploadista/typescript-config": "0.0.3"
27
+ },
28
+ "scripts": {
29
+ "format": "biome format --write ./src",
30
+ "lint": "biome lint --write ./src",
31
+ "check": "biome check --write ./src",
32
+ "test": "vitest",
33
+ "test:run": "vitest run",
34
+ "test:watch": "vitest --watch"
35
+ }
36
+ }