nuxt-upload-kit 0.1.1

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 (38) hide show
  1. package/README.md +171 -0
  2. package/dist/module.d.mts +14 -0
  3. package/dist/module.json +9 -0
  4. package/dist/module.mjs +29 -0
  5. package/dist/runtime/composables/useFFMpeg.d.ts +14 -0
  6. package/dist/runtime/composables/useFFMpeg.js +66 -0
  7. package/dist/runtime/composables/useUploadKit/index.d.ts +471 -0
  8. package/dist/runtime/composables/useUploadKit/index.js +486 -0
  9. package/dist/runtime/composables/useUploadKit/plugins/image-compressor.d.ts +56 -0
  10. package/dist/runtime/composables/useUploadKit/plugins/image-compressor.js +137 -0
  11. package/dist/runtime/composables/useUploadKit/plugins/index.d.ts +4 -0
  12. package/dist/runtime/composables/useUploadKit/plugins/index.js +4 -0
  13. package/dist/runtime/composables/useUploadKit/plugins/storage/azure-datalake.d.ts +55 -0
  14. package/dist/runtime/composables/useUploadKit/plugins/storage/azure-datalake.js +137 -0
  15. package/dist/runtime/composables/useUploadKit/plugins/storage/index.d.ts +10 -0
  16. package/dist/runtime/composables/useUploadKit/plugins/storage/index.js +1 -0
  17. package/dist/runtime/composables/useUploadKit/plugins/thumbnail-generator.d.ts +8 -0
  18. package/dist/runtime/composables/useUploadKit/plugins/thumbnail-generator.js +99 -0
  19. package/dist/runtime/composables/useUploadKit/plugins/video-compressor.d.ts +72 -0
  20. package/dist/runtime/composables/useUploadKit/plugins/video-compressor.js +111 -0
  21. package/dist/runtime/composables/useUploadKit/types.d.ts +488 -0
  22. package/dist/runtime/composables/useUploadKit/types.js +9 -0
  23. package/dist/runtime/composables/useUploadKit/utils.d.ts +23 -0
  24. package/dist/runtime/composables/useUploadKit/utils.js +45 -0
  25. package/dist/runtime/composables/useUploadKit/validators/allowed-file-types.d.ts +5 -0
  26. package/dist/runtime/composables/useUploadKit/validators/allowed-file-types.js +17 -0
  27. package/dist/runtime/composables/useUploadKit/validators/duplicate-file.d.ts +13 -0
  28. package/dist/runtime/composables/useUploadKit/validators/duplicate-file.js +27 -0
  29. package/dist/runtime/composables/useUploadKit/validators/index.d.ts +4 -0
  30. package/dist/runtime/composables/useUploadKit/validators/index.js +4 -0
  31. package/dist/runtime/composables/useUploadKit/validators/max-file-size.d.ts +5 -0
  32. package/dist/runtime/composables/useUploadKit/validators/max-file-size.js +17 -0
  33. package/dist/runtime/composables/useUploadKit/validators/max-files.d.ts +5 -0
  34. package/dist/runtime/composables/useUploadKit/validators/max-files.js +17 -0
  35. package/dist/runtime/types/index.d.ts +3 -0
  36. package/dist/runtime/types/index.js +3 -0
  37. package/dist/types.d.mts +5 -0
  38. package/package.json +84 -0
@@ -0,0 +1,488 @@
1
+ import type { Emitter } from "mitt";
2
+ /**
3
+ * PUBLIC API - Types users commonly need
4
+ * These are exported from the main package
5
+ */
6
+ export type FileStatus = "waiting" | "preprocessing" | "uploading" | "postprocessing" | "complete" | "error";
7
+ export type UploadStatus = "waiting" | "uploading";
8
+ export interface FileProgress {
9
+ percentage: number;
10
+ }
11
+ export interface FileError {
12
+ message: string;
13
+ details?: unknown;
14
+ }
15
+ /**
16
+ * File source - indicates where the file originated from
17
+ *
18
+ * - 'local': File selected from user's device
19
+ * - 'storage': File loaded from remote storage (was previously uploaded)
20
+ * - Cloud picker sources: Files picked from cloud providers (future)
21
+ * - 'instagram': Instagram picker
22
+ * - 'dropbox': Dropbox picker
23
+ * - 'google-drive': Google Drive picker
24
+ * - 'onedrive': OneDrive picker
25
+ * - ... add more as needed
26
+ */
27
+ export type FileSource = "local" | "storage" | "instagram" | "dropbox" | "google-drive" | "onedrive";
28
+ /**
29
+ * Base properties shared by both local and remote upload files
30
+ */
31
+ export interface BaseUploadFile<TUploadResult = any> {
32
+ /** Unique identifier for the file */
33
+ id: string;
34
+ /** Original filename (e.g., "vacation-photo.jpg") */
35
+ name: string;
36
+ /** File size in bytes */
37
+ size: number;
38
+ /** MIME type (e.g., "image/jpeg", "video/mp4") */
39
+ mimeType: string;
40
+ /**
41
+ * Current upload status
42
+ */
43
+ status: FileStatus;
44
+ /**
45
+ * Preview URL for displaying in UI (always populated after initialization)
46
+ * - For local files: Generated by thumbnail plugin as data URL, or remoteUrl after upload
47
+ * - For remote files: Provided by backend/storage, or falls back to remoteUrl
48
+ * - No manual fallback needed: Always available for display
49
+ */
50
+ preview?: string;
51
+ /** Upload progress tracking */
52
+ progress: FileProgress;
53
+ /** Error information if upload fails */
54
+ error?: FileError;
55
+ /**
56
+ * Result returned by the upload function/storage plugin
57
+ * Can contain additional metadata like etag, key, etc.
58
+ */
59
+ uploadResult?: TUploadResult;
60
+ /**
61
+ * Custom metadata for storing additional file information
62
+ * Plugins can add data here (e.g., { extension: 'jpg', originalWidth: 4000 })
63
+ */
64
+ meta: Record<string, unknown>;
65
+ }
66
+ /**
67
+ * Local upload file - originates from user's device
68
+ *
69
+ * Lifecycle:
70
+ * 1. User selects file → created with data, no remoteUrl
71
+ * 2. Validation → runs validate hooks
72
+ * 3. Preprocessing → generates thumbnails (preview set here)
73
+ * 4. User clicks upload → runs process hooks (compression)
74
+ * 5. Upload → remoteUrl set after successful upload
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * const localFile: LocalUploadFile = {
79
+ * source: 'local',
80
+ * data: fileBlob, // Has local data
81
+ * remoteUrl: undefined, // Not uploaded yet
82
+ * preview: 'data:image/jpeg;base64,...', // Generated by thumbnail plugin
83
+ * ...
84
+ * }
85
+ * ```
86
+ */
87
+ export interface LocalUploadFile<TUploadResult = any> extends BaseUploadFile<TUploadResult> {
88
+ /** Always 'local' for files selected from user's device */
89
+ source: "local";
90
+ /**
91
+ * The actual file data (File from input or Blob)
92
+ * Available for processing, compression, thumbnail generation, etc.
93
+ */
94
+ data: File | Blob;
95
+ /**
96
+ * URL where file was uploaded (set after successful upload)
97
+ * undefined before upload, populated after upload completes
98
+ * Use to check if file has been uploaded: `if (file.remoteUrl) { ... }`
99
+ */
100
+ remoteUrl?: string;
101
+ }
102
+ /**
103
+ * Remote upload file - originates from remote source
104
+ *
105
+ * These files already exist remotely and don't need uploading.
106
+ * Common sources:
107
+ * - 'storage': Previously uploaded files being re-loaded
108
+ * - 'instagram', 'dropbox', etc.: Files from cloud pickers
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * const remoteFile: RemoteUploadFile = {
113
+ * source: 'storage',
114
+ * data: null, // No local data - file is remote
115
+ * remoteUrl: 'https://storage.com/file.jpg', // Always present
116
+ * preview: 'https://storage.com/thumbnails/file.jpg', // Optional, from backend
117
+ * status: 'complete', // Already uploaded
118
+ * ...
119
+ * }
120
+ * ```
121
+ */
122
+ export interface RemoteUploadFile<TUploadResult = any> extends BaseUploadFile<TUploadResult> {
123
+ /**
124
+ * Source of the remote file
125
+ * - 'storage': File from your storage (previously uploaded)
126
+ * - 'instagram', 'dropbox', etc.: File from cloud picker
127
+ */
128
+ source: Exclude<FileSource, "local">;
129
+ /**
130
+ * Always null for remote files (no local data available)
131
+ * File exists remotely and is accessed via remoteUrl
132
+ */
133
+ data: null;
134
+ /**
135
+ * URL to the remote file (always present for remote files)
136
+ * Use this to display/download the file
137
+ */
138
+ remoteUrl: string;
139
+ }
140
+ /**
141
+ * Upload file discriminated union
142
+ * Use file.source to narrow the type in your code:
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * if (file.source === 'local') {
147
+ * // TypeScript knows: file is LocalUploadFile
148
+ * URL.createObjectURL(file.data)
149
+ * } else {
150
+ * // TypeScript knows: file is RemoteUploadFile
151
+ * console.log(file.remoteUrl)
152
+ * }
153
+ * ```
154
+ */
155
+ export type UploadFile<TUploadResult = any> = LocalUploadFile<TUploadResult> | RemoteUploadFile<TUploadResult>;
156
+ export type UploadFn<TUploadResult = any> = (file: UploadFile<TUploadResult>, onProgress: (progress: number) => void) => Promise<TUploadResult>;
157
+ export type GetRemoteFileFn = (fileId: string) => Promise<MinimumRemoteFileAttributes>;
158
+ export interface UploadOptions {
159
+ /**
160
+ * Storage plugin for uploading files (only one storage plugin can be active)
161
+ *
162
+ * Storage plugins handle the actual upload, download, and deletion of files
163
+ * from remote storage (Azure, S3, GCS, etc.)
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * storage: PluginAzureDataLake({
168
+ * sasURL: 'https://...',
169
+ * path: 'uploads'
170
+ * })
171
+ * ```
172
+ */
173
+ storage?: StoragePlugin<any, any>;
174
+ /**
175
+ * Processing and validation plugins (validators, compressors, etc.)
176
+ *
177
+ * These plugins run during the file lifecycle:
178
+ * - validate: Check file before adding
179
+ * - preprocess: Generate thumbnails/previews immediately
180
+ * - process: Compress/transform before upload
181
+ * - complete: Post-upload processing
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * plugins: [
186
+ * ValidatorMaxFiles({ maxFiles: 10 }),
187
+ * PluginImageCompressor({ quality: 0.8 })
188
+ * ]
189
+ * ```
190
+ */
191
+ plugins?: ProcessingPlugin<any, any>[];
192
+ /**
193
+ * Validate maximum number of files
194
+ * - false: disabled
195
+ * - number: enabled with limit
196
+ * @default false
197
+ */
198
+ maxFiles?: false | number;
199
+ /**
200
+ * Validate maximum file size in bytes
201
+ * - false: disabled
202
+ * - number: enabled with limit
203
+ * @default false
204
+ */
205
+ maxFileSize?: false | number;
206
+ /**
207
+ * Validate allowed file MIME types
208
+ * - false: disabled
209
+ * - string[]: enabled with allowed types
210
+ * @default false
211
+ */
212
+ allowedFileTypes?: false | string[];
213
+ /**
214
+ * Generate thumbnail previews for images/videos
215
+ * - false: disabled
216
+ * - true: enabled with defaults
217
+ * - object: enabled with custom options
218
+ * @default false
219
+ */
220
+ thumbnails?: false | true | ThumbnailOptions;
221
+ /**
222
+ * Compress images before upload
223
+ * - false: disabled
224
+ * - true: enabled with defaults
225
+ * - object: enabled with custom options
226
+ * @default false
227
+ */
228
+ imageCompression?: false | true | ImageCompressionOptions;
229
+ /**
230
+ * Automatically start upload after files are added
231
+ * @default false
232
+ */
233
+ autoProceed?: boolean;
234
+ }
235
+ export interface ThumbnailOptions {
236
+ width?: number;
237
+ height?: number;
238
+ quality?: number;
239
+ }
240
+ export interface ImageCompressionOptions {
241
+ maxWidth?: number;
242
+ maxHeight?: number;
243
+ quality?: number;
244
+ outputFormat?: "jpeg" | "webp" | "png" | "auto";
245
+ minSizeToCompress?: number;
246
+ preserveMetadata?: boolean;
247
+ }
248
+ type CoreUploaderEvents<TUploadResult = any> = {
249
+ "file:added": Readonly<UploadFile<TUploadResult>>;
250
+ "file:removed": Readonly<UploadFile<TUploadResult>>;
251
+ "file:replaced": Readonly<UploadFile<TUploadResult>>;
252
+ "file:processing": Readonly<UploadFile<TUploadResult>>;
253
+ "file:error": {
254
+ file: Readonly<UploadFile<TUploadResult>>;
255
+ error: FileError;
256
+ };
257
+ "upload:start": Array<Readonly<UploadFile<TUploadResult>>>;
258
+ "upload:complete": Array<Required<Readonly<UploadFile<TUploadResult>>>>;
259
+ "upload:error": FileError;
260
+ "upload:progress": {
261
+ file: Readonly<UploadFile<TUploadResult>>;
262
+ progress: number;
263
+ };
264
+ "files:reorder": {
265
+ oldIndex: number;
266
+ newIndex: number;
267
+ };
268
+ };
269
+ export type UploaderEvents<TUploadResult = any> = CoreUploaderEvents<TUploadResult>;
270
+ /**
271
+ * PLUGIN API - Types for building custom plugins
272
+ * Only needed if users want to create custom validators/processors
273
+ */
274
+ export type PluginContext<TPluginEvents extends Record<string, any> = Record<string, never>> = {
275
+ files: UploadFile[];
276
+ options: UploadOptions;
277
+ /**
278
+ * Emit custom plugin events
279
+ * Events are automatically prefixed with the plugin ID
280
+ */
281
+ emit: <K extends keyof TPluginEvents>(event: K, payload: TPluginEvents[K]) => void;
282
+ };
283
+ export type ValidationHook<TPluginEvents extends Record<string, any> = Record<string, never>> = (file: UploadFile, context: PluginContext<TPluginEvents>) => Promise<true | UploadFile>;
284
+ export type ProcessingHook<TPluginEvents extends Record<string, any> = Record<string, never>> = (file: UploadFile, context: PluginContext<TPluginEvents>) => Promise<UploadFile>;
285
+ export type SetupHook<TPluginEvents extends Record<string, any> = Record<string, never>> = (context: PluginContext<TPluginEvents>) => Promise<void>;
286
+ /**
287
+ * Storage hooks for handling upload/download/deletion operations
288
+ *
289
+ * Storage plugins MUST return an object containing a `url` property.
290
+ * This URL will be set as the file's `remoteUrl` after successful upload.
291
+ *
292
+ * @example
293
+ * ```typescript
294
+ * upload: async (file, context) => {
295
+ * // Upload logic...
296
+ * return {
297
+ * url: 'https://storage.example.com/file.jpg', // Required
298
+ * key: 'uploads/file.jpg', // Optional
299
+ * etag: 'abc123' // Optional
300
+ * }
301
+ * }
302
+ * ```
303
+ */
304
+ export type UploadHook<TUploadResult = any, TPluginEvents extends Record<string, any> = Record<string, never>> = (file: UploadFile<TUploadResult>, context: PluginContext<TPluginEvents> & {
305
+ onProgress: (progress: number) => void;
306
+ }) => Promise<TUploadResult & {
307
+ url: string;
308
+ }>;
309
+ export type GetRemoteFileHook<TPluginEvents extends Record<string, any> = Record<string, never>> = (fileId: string, context: PluginContext<TPluginEvents>) => Promise<MinimumRemoteFileAttributes>;
310
+ export type RemoveHook<TPluginEvents extends Record<string, any> = Record<string, never>> = (file: UploadFile, context: PluginContext<TPluginEvents>) => Promise<void>;
311
+ export type PluginLifecycleStage = "validate" | "preprocess" | "process" | "upload" | "complete";
312
+ /**
313
+ * Processing plugin hooks (validators, compressors, thumbnail generators)
314
+ */
315
+ export type ProcessingPluginHooks<TPluginEvents extends Record<string, any> = Record<string, never>> = {
316
+ validate?: ValidationHook<TPluginEvents>;
317
+ preprocess?: ProcessingHook<TPluginEvents>;
318
+ process?: ProcessingHook<TPluginEvents>;
319
+ complete?: ProcessingHook<TPluginEvents>;
320
+ };
321
+ /**
322
+ * Storage plugin hooks (upload, download, delete from remote storage)
323
+ */
324
+ export type StoragePluginHooks<TUploadResult = any, TPluginEvents extends Record<string, any> = Record<string, never>> = {
325
+ upload: UploadHook<TUploadResult, TPluginEvents>;
326
+ getRemoteFile?: GetRemoteFileHook<TPluginEvents>;
327
+ remove?: RemoveHook<TPluginEvents>;
328
+ };
329
+ /**
330
+ * All possible plugin hooks (for internal use)
331
+ */
332
+ export type PluginHooks<TUploadResult = any, TPluginEvents extends Record<string, any> = Record<string, never>> = {
333
+ validate?: ValidationHook<TPluginEvents>;
334
+ preprocess?: ProcessingHook<TPluginEvents>;
335
+ process?: ProcessingHook<TPluginEvents>;
336
+ upload?: UploadHook<TUploadResult, TPluginEvents>;
337
+ getRemoteFile?: GetRemoteFileHook<TPluginEvents>;
338
+ remove?: RemoveHook<TPluginEvents>;
339
+ complete?: ProcessingHook<TPluginEvents>;
340
+ };
341
+ /**
342
+ * Processing plugin (validators, compressors, thumbnail generators)
343
+ *
344
+ * These plugins transform or validate files without handling storage.
345
+ */
346
+ export interface ProcessingPlugin<_TUploadResult = any, TPluginEvents extends Record<string, any> = Record<string, never>> {
347
+ id: string;
348
+ hooks: ProcessingPluginHooks<TPluginEvents>;
349
+ options?: UploadOptions;
350
+ events?: TPluginEvents;
351
+ }
352
+ /**
353
+ * Storage plugin (Azure, S3, GCS, etc.)
354
+ *
355
+ * Storage plugins handle uploading, downloading, and deleting files from remote storage.
356
+ * Only one storage plugin can be active at a time.
357
+ */
358
+ export interface StoragePlugin<TUploadResult = any, TPluginEvents extends Record<string, any> = Record<string, never>> {
359
+ id: string;
360
+ hooks: StoragePluginHooks<TUploadResult, TPluginEvents>;
361
+ options?: UploadOptions;
362
+ events?: TPluginEvents;
363
+ }
364
+ /**
365
+ * Base plugin interface (for internal use - supports both types)
366
+ */
367
+ export interface Plugin<TUploadResult = any, TPluginEvents extends Record<string, any> = Record<string, never>> {
368
+ id: string;
369
+ hooks: PluginHooks<TUploadResult, TPluginEvents>;
370
+ options?: UploadOptions;
371
+ events?: TPluginEvents;
372
+ }
373
+ /**
374
+ * Define a processing plugin (validators, compressors, thumbnail generators)
375
+ *
376
+ * @example Validator
377
+ * ```typescript
378
+ * export const ValidatorMaxFiles = defineProcessingPlugin<ValidatorOptions>((options) => ({
379
+ * id: 'validator-max-files',
380
+ * hooks: {
381
+ * validate: async (file, context) => {
382
+ * if (context.files.length >= options.maxFiles) {
383
+ * throw { message: 'Too many files' }
384
+ * }
385
+ * return file
386
+ * }
387
+ * }
388
+ * }))
389
+ * ```
390
+ */
391
+ export declare function defineProcessingPlugin<TPluginOptions = unknown, TPluginEvents extends Record<string, any> = Record<string, never>>(factory: (options: TPluginOptions) => ProcessingPlugin<any, TPluginEvents>): (options: TPluginOptions) => ProcessingPlugin<any, TPluginEvents>;
392
+ /**
393
+ * Define a storage plugin (Azure, S3, GCS, etc.)
394
+ *
395
+ * Storage plugins MUST implement the `upload` hook and should return an object with a `url` property.
396
+ *
397
+ * @example Azure Storage
398
+ * ```typescript
399
+ * export const PluginAzureDataLake = defineStoragePlugin<AzureOptions, AzureEvents>((options) => ({
400
+ * id: 'azure-datalake-storage',
401
+ * hooks: {
402
+ * upload: async (file, context) => {
403
+ * const fileClient = await getFileClient(file.id)
404
+ * await fileClient.upload(file.data, { onProgress: context.onProgress })
405
+ * return { url: fileClient.url, blobPath: fileClient.name }
406
+ * },
407
+ * getRemoteFile: async (fileId, context) => {
408
+ * // ... fetch file metadata ...
409
+ * },
410
+ * remove: async (file, context) => {
411
+ * // ... delete file ...
412
+ * }
413
+ * }
414
+ * }))
415
+ * ```
416
+ */
417
+ export declare function defineStoragePlugin<TPluginOptions = unknown, TUploadResult = any, TPluginEvents extends Record<string, any> = Record<string, never>>(factory: (options: TPluginOptions) => StoragePlugin<TUploadResult, TPluginEvents>): (options: TPluginOptions) => StoragePlugin<TUploadResult, TPluginEvents>;
418
+ /**
419
+ * Define an uploader plugin with type safety, context access, and custom events.
420
+ * This is the universal plugin factory for all plugin types (storage, validators, processors).
421
+ *
422
+ * @deprecated Use defineProcessingPlugin or defineStoragePlugin instead for better type safety
423
+ *
424
+ * Hooks receive context as a parameter, making it clear when context is available.
425
+ * Context includes current files, options, and an emit function for custom events.
426
+ *
427
+ * @example Basic Plugin
428
+ * ```typescript
429
+ * export const ValidatorMaxFiles = defineUploaderPlugin<ValidatorOptions>((options) => ({
430
+ * id: 'validator-max-files',
431
+ * hooks: {
432
+ * validate: async (file, context) => {
433
+ * if (context.files.length >= options.maxFiles) {
434
+ * throw { message: 'Too many files' }
435
+ * }
436
+ * return file
437
+ * }
438
+ * }
439
+ * }))
440
+ * ```
441
+ *
442
+ * @example Plugin with Custom Events
443
+ * ```typescript
444
+ * type CompressionEvents = {
445
+ * start: { file: UploadFile; originalSize: number }
446
+ * complete: { file: UploadFile; savedBytes: number }
447
+ * }
448
+ *
449
+ * export const PluginImageCompressor = defineUploaderPlugin<
450
+ * ImageCompressorOptions,
451
+ * CompressionEvents
452
+ * >((options) => ({
453
+ * id: 'image-compressor',
454
+ * hooks: {
455
+ * process: async (file, context) => {
456
+ * context.emit('start', { file, originalSize: file.size })
457
+ * // ... compression logic ...
458
+ * context.emit('complete', { file, savedBytes: 1000 })
459
+ * return file
460
+ * }
461
+ * }
462
+ * }))
463
+ *
464
+ * // Usage - events are automatically prefixed with plugin ID
465
+ * uploader.on('image-compressor:complete', ({ file, savedBytes }) => {
466
+ * console.log(`Saved ${savedBytes} bytes`)
467
+ * })
468
+ * ```
469
+ */
470
+ export declare function defineUploaderPlugin<TPluginOptions = unknown, TPluginEvents extends Record<string, any> = Record<string, never>>(factory: (options: TPluginOptions) => Plugin<any, TPluginEvents>): (options: TPluginOptions) => Plugin<any, TPluginEvents>;
471
+ /**
472
+ * INTERNAL TYPES - Not commonly needed by users
473
+ * Kept exported for edge cases but not primary API
474
+ */
475
+ export type PreProcessor = (file: UploadFile) => Promise<UploadFile>;
476
+ export type Uploader = (file: Readonly<UploadFile>, emiter: Emitter<Pick<UploaderEvents, "upload:error" | "upload:progress">>) => Promise<string>;
477
+ export type Validator = (file: UploadFile) => Promise<boolean | FileError>;
478
+ export type Processor = (file: UploadFile) => Promise<File | Blob>;
479
+ export interface UploadBlob {
480
+ blobPath: string;
481
+ }
482
+ type MinimumRemoteFileAttributes = {
483
+ size: number;
484
+ mimeType: string;
485
+ remoteUrl: string;
486
+ preview?: string;
487
+ };
488
+ export {};
@@ -0,0 +1,9 @@
1
+ export function defineProcessingPlugin(factory) {
2
+ return factory;
3
+ }
4
+ export function defineStoragePlugin(factory) {
5
+ return factory;
6
+ }
7
+ export function defineUploaderPlugin(factory) {
8
+ return factory;
9
+ }
@@ -0,0 +1,23 @@
1
+ import type { PluginContext, UploadFile, FileError, UploadOptions } from "./types.js";
2
+ import type { Emitter } from "mitt";
3
+ /**
4
+ * Create a plugin context object with consistent structure
5
+ */
6
+ export declare function createPluginContext<TPluginEvents extends Record<string, any> = Record<string, never>>(pluginId: string, files: UploadFile[], options: UploadOptions, emitter: Emitter<any>): PluginContext<TPluginEvents>;
7
+ /**
8
+ * Create a consistent file error object
9
+ */
10
+ export declare function createFileError(file: UploadFile, error: unknown): FileError;
11
+ /**
12
+ * Calculate thumbnail dimensions while maintaining aspect ratio
13
+ */
14
+ export declare function calculateThumbnailDimensions(originalWidth: number, originalHeight: number, maxWidth: number, maxHeight: number): {
15
+ width: number;
16
+ height: number;
17
+ };
18
+ /**
19
+ * Cleanup object URLs to prevent memory leaks
20
+ * @param urlMap Map of file IDs to object URLs
21
+ * @param fileId Optional file ID to cleanup specific URL, or cleanup all if not provided
22
+ */
23
+ export declare function cleanupObjectURLs(urlMap: Map<string, string>, fileId?: string): void;
@@ -0,0 +1,45 @@
1
+ export function createPluginContext(pluginId, files, options, emitter) {
2
+ return {
3
+ files,
4
+ options,
5
+ emit: (event, payload) => {
6
+ const prefixedEvent = `${pluginId}:${String(event)}`;
7
+ emitter.emit(prefixedEvent, payload);
8
+ }
9
+ };
10
+ }
11
+ export function createFileError(file, error) {
12
+ return {
13
+ message: error instanceof Error ? error.message : String(error),
14
+ details: {
15
+ fileName: file.name,
16
+ fileSize: file.size,
17
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
18
+ }
19
+ };
20
+ }
21
+ export function calculateThumbnailDimensions(originalWidth, originalHeight, maxWidth, maxHeight) {
22
+ const aspectRatio = originalWidth / originalHeight;
23
+ let width = maxWidth;
24
+ let height = maxHeight;
25
+ if (aspectRatio > 1) {
26
+ height = maxWidth / aspectRatio;
27
+ } else {
28
+ width = maxHeight * aspectRatio;
29
+ }
30
+ return { width, height };
31
+ }
32
+ export function cleanupObjectURLs(urlMap, fileId) {
33
+ if (fileId) {
34
+ const url = urlMap.get(fileId);
35
+ if (url) {
36
+ URL.revokeObjectURL(url);
37
+ urlMap.delete(fileId);
38
+ }
39
+ } else {
40
+ for (const url of urlMap.values()) {
41
+ URL.revokeObjectURL(url);
42
+ }
43
+ urlMap.clear();
44
+ }
45
+ }
@@ -0,0 +1,5 @@
1
+ interface ValidatorAllowedFileTypesOptions {
2
+ allowedFileTypes?: string[];
3
+ }
4
+ export declare const ValidatorAllowedFileTypes: (options: ValidatorAllowedFileTypesOptions) => import("../types.js").ProcessingPlugin<any, Record<string, never>>;
5
+ export {};
@@ -0,0 +1,17 @@
1
+ import { defineProcessingPlugin } from "../types.js";
2
+ export const ValidatorAllowedFileTypes = defineProcessingPlugin((options) => {
3
+ return {
4
+ id: "validator-allowed-file-types",
5
+ hooks: {
6
+ validate: async (file, _context) => {
7
+ if (!options.allowedFileTypes || options.allowedFileTypes.length === 0) {
8
+ return file;
9
+ }
10
+ if (options.allowedFileTypes.includes(file.mimeType)) {
11
+ return file;
12
+ }
13
+ throw { message: `File type ${file.mimeType} is not allowed` };
14
+ }
15
+ }
16
+ };
17
+ });
@@ -0,0 +1,13 @@
1
+ interface ValidatorDuplicateFileOptions {
2
+ /**
3
+ * Whether to allow duplicate files
4
+ * @default false
5
+ */
6
+ allowDuplicates?: boolean;
7
+ /**
8
+ * Custom error message for duplicates
9
+ */
10
+ errorMessage?: string;
11
+ }
12
+ export declare const ValidatorDuplicateFile: (options: ValidatorDuplicateFileOptions) => import("../types.js").Plugin<any, Record<string, never>>;
13
+ export {};
@@ -0,0 +1,27 @@
1
+ import { defineUploaderPlugin } from "../types.js";
2
+ export const ValidatorDuplicateFile = defineUploaderPlugin((options) => {
3
+ const { allowDuplicates = false, errorMessage = "This file has already been added" } = options;
4
+ return {
5
+ id: "validator-duplicate-file",
6
+ hooks: {
7
+ validate: async (file, context) => {
8
+ if (allowDuplicates) {
9
+ return file;
10
+ }
11
+ const isDuplicate = context.files.some((existingFile) => {
12
+ const sameSize = existingFile.size === file.size;
13
+ const sameName = existingFile.name === file.name;
14
+ let sameDate = true;
15
+ if (file.data instanceof File && existingFile.data instanceof File) {
16
+ sameDate = existingFile.data.lastModified === file.data.lastModified;
17
+ }
18
+ return sameSize && sameName && sameDate;
19
+ });
20
+ if (isDuplicate) {
21
+ throw { message: errorMessage, details: { fileName: file.name } };
22
+ }
23
+ return file;
24
+ }
25
+ }
26
+ };
27
+ });
@@ -0,0 +1,4 @@
1
+ export * from "./allowed-file-types.js";
2
+ export * from "./max-file-size.js";
3
+ export * from "./max-files.js";
4
+ export * from "./duplicate-file.js";
@@ -0,0 +1,4 @@
1
+ export * from "./allowed-file-types.js";
2
+ export * from "./max-file-size.js";
3
+ export * from "./max-files.js";
4
+ export * from "./duplicate-file.js";
@@ -0,0 +1,5 @@
1
+ interface ValidatorMaxFileSizeOptions {
2
+ maxFileSize?: number;
3
+ }
4
+ export declare const ValidatorMaxFileSize: (options: ValidatorMaxFileSizeOptions) => import("../types.js").ProcessingPlugin<any, Record<string, never>>;
5
+ export {};
@@ -0,0 +1,17 @@
1
+ import { defineProcessingPlugin } from "../types.js";
2
+ export const ValidatorMaxFileSize = defineProcessingPlugin((options) => {
3
+ return {
4
+ id: "validator-max-file-size",
5
+ hooks: {
6
+ validate: async (file, _context) => {
7
+ if (!options.maxFileSize || options.maxFileSize === Infinity) {
8
+ return file;
9
+ }
10
+ if (file.size <= options.maxFileSize) {
11
+ return file;
12
+ }
13
+ throw { message: `File size exceeds the maximum limit of ${options.maxFileSize} bytes` };
14
+ }
15
+ }
16
+ };
17
+ });
@@ -0,0 +1,5 @@
1
+ interface ValidatorMaxFilesOptions {
2
+ maxFiles?: number;
3
+ }
4
+ export declare const ValidatorMaxFiles: (options: ValidatorMaxFilesOptions) => import("../types.js").ProcessingPlugin<any, Record<string, never>>;
5
+ export {};