nuxt-upload-kit 0.1.23 → 0.1.25
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/dist/module.json +1 -1
- package/dist/runtime/composables/useUploadKit/file-operations.js +1 -1
- package/dist/runtime/composables/useUploadKit/index.d.ts +16 -0
- package/dist/runtime/composables/useUploadKit/index.js +6 -4
- package/dist/runtime/composables/useUploadKit/plugin-runner.d.ts +2 -1
- package/dist/runtime/composables/useUploadKit/plugin-runner.js +3 -1
- package/dist/runtime/composables/useUploadKit/plugins/storage/azure-datalake.js +20 -0
- package/dist/runtime/composables/useUploadKit/plugins/storage/firebase-storage.js +6 -0
- package/dist/runtime/composables/useUploadKit/plugins/storage/s3.js +17 -0
- package/dist/runtime/composables/useUploadKit/plugins/thumbnail-generator.d.ts +1 -0
- package/dist/runtime/composables/useUploadKit/plugins/thumbnail-generator.js +19 -1
- package/dist/runtime/composables/useUploadKit/types.d.ts +66 -0
- package/dist/runtime/composables/useUploadKit/utils.d.ts +12 -2
- package/dist/runtime/composables/useUploadKit/utils.js +20 -1
- package/package.json +11 -11
package/dist/module.json
CHANGED
|
@@ -117,7 +117,7 @@ export function createFileOperations(deps) {
|
|
|
117
117
|
const storagePlugin = getStoragePlugin();
|
|
118
118
|
if (storagePlugin?.hooks.remove) {
|
|
119
119
|
try {
|
|
120
|
-
const context = createPluginContext(storagePlugin.id, files.value, options, emitter);
|
|
120
|
+
const context = createPluginContext(storagePlugin.id, files.value, options, emitter, storagePlugin);
|
|
121
121
|
await storagePlugin.hooks.remove(file, context);
|
|
122
122
|
} catch (error) {
|
|
123
123
|
console.error(`Storage plugin remove error:`, error);
|
|
@@ -71,6 +71,10 @@ export declare const useUploadKit: <TUploadResult = any>(_options?: UploadOption
|
|
|
71
71
|
readonly meta: {
|
|
72
72
|
readonly [x: string]: Readonly<unknown>;
|
|
73
73
|
};
|
|
74
|
+
readonly thumbnail?: {
|
|
75
|
+
readonly url: string;
|
|
76
|
+
readonly storageKey: string;
|
|
77
|
+
} | undefined;
|
|
74
78
|
} | {
|
|
75
79
|
readonly source: Exclude<import("./types.js").FileSource, "local">;
|
|
76
80
|
readonly data: null;
|
|
@@ -93,6 +97,10 @@ export declare const useUploadKit: <TUploadResult = any>(_options?: UploadOption
|
|
|
93
97
|
readonly meta: {
|
|
94
98
|
readonly [x: string]: Readonly<unknown>;
|
|
95
99
|
};
|
|
100
|
+
readonly thumbnail?: {
|
|
101
|
+
readonly url: string;
|
|
102
|
+
readonly storageKey: string;
|
|
103
|
+
} | undefined;
|
|
96
104
|
})[], readonly ({
|
|
97
105
|
readonly source: "local";
|
|
98
106
|
readonly data: {
|
|
@@ -164,6 +172,10 @@ export declare const useUploadKit: <TUploadResult = any>(_options?: UploadOption
|
|
|
164
172
|
readonly meta: {
|
|
165
173
|
readonly [x: string]: Readonly<unknown>;
|
|
166
174
|
};
|
|
175
|
+
readonly thumbnail?: {
|
|
176
|
+
readonly url: string;
|
|
177
|
+
readonly storageKey: string;
|
|
178
|
+
} | undefined;
|
|
167
179
|
} | {
|
|
168
180
|
readonly source: Exclude<import("./types.js").FileSource, "local">;
|
|
169
181
|
readonly data: null;
|
|
@@ -186,6 +198,10 @@ export declare const useUploadKit: <TUploadResult = any>(_options?: UploadOption
|
|
|
186
198
|
readonly meta: {
|
|
187
199
|
readonly [x: string]: Readonly<unknown>;
|
|
188
200
|
};
|
|
201
|
+
readonly thumbnail?: {
|
|
202
|
+
readonly url: string;
|
|
203
|
+
readonly storageKey: string;
|
|
204
|
+
} | undefined;
|
|
189
205
|
})[]>>;
|
|
190
206
|
totalProgress: import("vue").ComputedRef<number>;
|
|
191
207
|
isReady: Readonly<import("vue").Ref<boolean, boolean>>;
|
|
@@ -48,7 +48,8 @@ export const useUploadKit = (_options = {}) => {
|
|
|
48
48
|
PluginThumbnailGenerator({
|
|
49
49
|
maxWidth: thumbOpts.width ?? 128,
|
|
50
50
|
maxHeight: thumbOpts.height ?? 128,
|
|
51
|
-
quality: thumbOpts.quality ?? 1
|
|
51
|
+
quality: thumbOpts.quality ?? 1,
|
|
52
|
+
upload: thumbOpts.upload ?? false
|
|
52
53
|
})
|
|
53
54
|
);
|
|
54
55
|
}
|
|
@@ -65,7 +66,7 @@ export const useUploadKit = (_options = {}) => {
|
|
|
65
66
|
})
|
|
66
67
|
);
|
|
67
68
|
}
|
|
68
|
-
const { getPluginEmitFn, runPluginStage } = createPluginRunner({ options, files, emitter });
|
|
69
|
+
const { getPluginEmitFn, runPluginStage } = createPluginRunner({ options, files, emitter, getStoragePlugin });
|
|
69
70
|
const uploadHolder = { fn: async () => {
|
|
70
71
|
} };
|
|
71
72
|
const fileOps = createFileOperations({
|
|
@@ -100,7 +101,7 @@ export const useUploadKit = (_options = {}) => {
|
|
|
100
101
|
if (!storagePlugin?.hooks.getRemoteFile) {
|
|
101
102
|
throw new Error("Storage plugin with getRemoteFile hook is required to initialize existing files");
|
|
102
103
|
}
|
|
103
|
-
const context = createPluginContext(storagePlugin.id, files.value, options, emitter);
|
|
104
|
+
const context = createPluginContext(storagePlugin.id, files.value, options, emitter, storagePlugin);
|
|
104
105
|
const remoteFileData = await storagePlugin.hooks.getRemoteFile(storageKey, context);
|
|
105
106
|
const id = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
106
107
|
const name = storageKey.split("/").pop() || storageKey;
|
|
@@ -205,7 +206,8 @@ export const useUploadKit = (_options = {}) => {
|
|
|
205
206
|
const currentFile = files.value.find((f) => f.id === processedFile.id);
|
|
206
207
|
const preview = currentFile?.preview || remoteUrl;
|
|
207
208
|
const storageKey = extractStorageKey(uploadResult);
|
|
208
|
-
|
|
209
|
+
const thumbnail = currentFile?.thumbnail;
|
|
210
|
+
updateFile(processedFile.id, { status: "complete", uploadResult, remoteUrl, preview, storageKey, thumbnail });
|
|
209
211
|
};
|
|
210
212
|
const upload = async () => {
|
|
211
213
|
const filesToUpload = files.value.filter((f) => f.status === "waiting");
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { Ref } from "vue";
|
|
2
2
|
import type { Emitter } from "mitt";
|
|
3
|
-
import type { UploadFile, UploadOptions, PluginLifecycleStage } from "./types.js";
|
|
3
|
+
import type { UploadFile, UploadOptions, PluginLifecycleStage, StoragePlugin } from "./types.js";
|
|
4
4
|
type EmitFn = <K extends string | number | symbol>(event: K, payload: any) => void;
|
|
5
5
|
export interface PluginRunnerDeps<TUploadResult = any> {
|
|
6
6
|
options: UploadOptions;
|
|
7
7
|
files: Ref<UploadFile<TUploadResult>[]>;
|
|
8
8
|
emitter: Emitter<any>;
|
|
9
|
+
getStoragePlugin: () => StoragePlugin<any, any> | null;
|
|
9
10
|
}
|
|
10
11
|
/**
|
|
11
12
|
* Creates the plugin execution system with cached emit functions
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export function createPluginRunner(deps) {
|
|
2
|
-
const { options, files, emitter } = deps;
|
|
2
|
+
const { options, files, emitter, getStoragePlugin } = deps;
|
|
3
3
|
const pluginEmitFunctions = /* @__PURE__ */ new Map();
|
|
4
4
|
const getPluginEmitFn = (pluginId) => {
|
|
5
5
|
let emitFn = pluginEmitFunctions.get(pluginId);
|
|
@@ -34,9 +34,11 @@ export function createPluginRunner(deps) {
|
|
|
34
34
|
const hook = plugin.hooks[stage];
|
|
35
35
|
if (!hook) continue;
|
|
36
36
|
try {
|
|
37
|
+
const storage = getStoragePlugin();
|
|
37
38
|
const context = {
|
|
38
39
|
files: files.value,
|
|
39
40
|
options,
|
|
41
|
+
storage: storage || void 0,
|
|
40
42
|
emit: getPluginEmitFn(plugin.id)
|
|
41
43
|
};
|
|
42
44
|
const result = await callPluginHook(hook, stage, currentFile, context);
|
|
@@ -97,6 +97,26 @@ export const PluginAzureDataLake = defineStorageAdapter((options) => {
|
|
|
97
97
|
};
|
|
98
98
|
return {
|
|
99
99
|
id: "azure-datalake-storage",
|
|
100
|
+
async upload(data, storageKey, uploadOptions) {
|
|
101
|
+
const requestKey = buildFullStorageKey(storageKey, true);
|
|
102
|
+
const fileClient = await getFileClient(requestKey, "upload");
|
|
103
|
+
const contentType = uploadOptions?.contentType || "application/octet-stream";
|
|
104
|
+
await fileClient.upload(data, {
|
|
105
|
+
pathHttpHeaders: {
|
|
106
|
+
...options.pathHttpHeaders,
|
|
107
|
+
contentType
|
|
108
|
+
},
|
|
109
|
+
onProgress: uploadOptions?.onProgress ? ({ loadedBytes }) => {
|
|
110
|
+
const percentage = Math.round(loadedBytes / data.size * 100);
|
|
111
|
+
uploadOptions.onProgress(percentage);
|
|
112
|
+
} : void 0
|
|
113
|
+
});
|
|
114
|
+
const actualStorageKey = getBlobPathFromUrl(fileClient.url) || requestKey;
|
|
115
|
+
return {
|
|
116
|
+
url: fileClient.url,
|
|
117
|
+
storageKey: actualStorageKey
|
|
118
|
+
};
|
|
119
|
+
},
|
|
100
120
|
hooks: {
|
|
101
121
|
/**
|
|
102
122
|
* Upload file to Azure Blob Storage
|
|
@@ -56,6 +56,12 @@ export const PluginFirebaseStorage = defineStorageAdapter((options) => {
|
|
|
56
56
|
};
|
|
57
57
|
return {
|
|
58
58
|
id: "firebase-storage",
|
|
59
|
+
async upload(data, storageKey, uploadOptions) {
|
|
60
|
+
const fullKey = buildFullStorageKey(storageKey);
|
|
61
|
+
const contentType = uploadOptions?.contentType || "application/octet-stream";
|
|
62
|
+
return uploadToFirebase(fullKey, data, contentType, storageKey, uploadOptions?.onProgress || (() => {
|
|
63
|
+
}));
|
|
64
|
+
},
|
|
59
65
|
hooks: {
|
|
60
66
|
/**
|
|
61
67
|
* Upload file to Firebase Storage
|
|
@@ -33,6 +33,23 @@ export const PluginS3 = defineStorageAdapter((options) => {
|
|
|
33
33
|
}
|
|
34
34
|
return {
|
|
35
35
|
id: "s3-storage",
|
|
36
|
+
async upload(data, storageKey, uploadOptions) {
|
|
37
|
+
return withRetry(async () => {
|
|
38
|
+
const fullKey = buildFullStorageKey(storageKey);
|
|
39
|
+
const contentType = uploadOptions?.contentType || "application/octet-stream";
|
|
40
|
+
const { uploadUrl, publicUrl } = await options.getPresignedUploadUrl(fullKey, contentType, {
|
|
41
|
+
fileName: storageKey,
|
|
42
|
+
fileSize: data.size
|
|
43
|
+
});
|
|
44
|
+
const etag = await uploadWithProgress(uploadUrl, data, contentType, uploadOptions?.onProgress || (() => {
|
|
45
|
+
}));
|
|
46
|
+
return {
|
|
47
|
+
url: publicUrl,
|
|
48
|
+
storageKey: fullKey,
|
|
49
|
+
etag
|
|
50
|
+
};
|
|
51
|
+
}, `Standalone upload "${storageKey}"`);
|
|
52
|
+
},
|
|
36
53
|
hooks: {
|
|
37
54
|
/**
|
|
38
55
|
* Upload file to S3 using presigned URL
|
|
@@ -3,6 +3,7 @@ interface ThumbnailGeneratorOptions {
|
|
|
3
3
|
maxHeight?: number;
|
|
4
4
|
quality?: number;
|
|
5
5
|
videoCaptureTime?: number;
|
|
6
|
+
upload?: boolean;
|
|
6
7
|
}
|
|
7
8
|
export declare const PluginThumbnailGenerator: (options: ThumbnailGeneratorOptions) => import("../types.js").ProcessingPlugin<any, Record<string, never>>;
|
|
8
9
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineProcessingPlugin } from "../types.js";
|
|
2
|
-
import { calculateThumbnailDimensions } from "../utils.js";
|
|
2
|
+
import { calculateThumbnailDimensions, dataUrlToBlob, deriveThumbnailKey } from "../utils.js";
|
|
3
3
|
export const PluginThumbnailGenerator = defineProcessingPlugin((pluginOptions) => {
|
|
4
4
|
return {
|
|
5
5
|
id: "thumbnail-generator",
|
|
@@ -35,6 +35,24 @@ export const PluginThumbnailGenerator = defineProcessingPlugin((pluginOptions) =
|
|
|
35
35
|
URL.revokeObjectURL(sourceUrl);
|
|
36
36
|
}
|
|
37
37
|
return file;
|
|
38
|
+
},
|
|
39
|
+
process: async (file, context) => {
|
|
40
|
+
const { upload = false } = pluginOptions;
|
|
41
|
+
if (upload && context.storage && file.preview?.startsWith("data:")) {
|
|
42
|
+
try {
|
|
43
|
+
const thumbnailBlob = dataUrlToBlob(file.preview);
|
|
44
|
+
const thumbnailKey = deriveThumbnailKey(file.id);
|
|
45
|
+
const thumbnailResult = await context.storage.upload(thumbnailBlob, thumbnailKey, {
|
|
46
|
+
contentType: thumbnailBlob.type
|
|
47
|
+
});
|
|
48
|
+
file.thumbnail = { url: thumbnailResult.url, storageKey: thumbnailResult.storageKey };
|
|
49
|
+
} catch (err) {
|
|
50
|
+
if (import.meta.dev) {
|
|
51
|
+
console.warn(`[thumbnail-generator] Thumbnail upload failed for "${file.name}":`, err);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return file;
|
|
38
56
|
}
|
|
39
57
|
}
|
|
40
58
|
};
|
|
@@ -81,6 +81,14 @@ export interface BaseUploadFile<TUploadResult = any> {
|
|
|
81
81
|
* Plugins can add data here (e.g., { extension: 'jpg', originalWidth: 4000 })
|
|
82
82
|
*/
|
|
83
83
|
meta: Record<string, unknown>;
|
|
84
|
+
/**
|
|
85
|
+
* Thumbnail upload result (populated when `thumbnails.upload` is enabled).
|
|
86
|
+
* Contains the URL and storage key for the uploaded thumbnail.
|
|
87
|
+
*/
|
|
88
|
+
thumbnail?: {
|
|
89
|
+
url: string;
|
|
90
|
+
storageKey: string;
|
|
91
|
+
};
|
|
84
92
|
}
|
|
85
93
|
/**
|
|
86
94
|
* Local upload file - originates from user's device
|
|
@@ -272,6 +280,26 @@ export interface ThumbnailOptions {
|
|
|
272
280
|
width?: number;
|
|
273
281
|
height?: number;
|
|
274
282
|
quality?: number;
|
|
283
|
+
/**
|
|
284
|
+
* Upload generated thumbnails to storage alongside main files.
|
|
285
|
+
* Requires a storage adapter with standalone upload support.
|
|
286
|
+
*
|
|
287
|
+
* When enabled, after each file uploads, its thumbnail preview
|
|
288
|
+
* is converted to a Blob and uploaded using `storage.upload()`.
|
|
289
|
+
* The result is stored on `file.thumbnail`.
|
|
290
|
+
*
|
|
291
|
+
* @default false
|
|
292
|
+
*/
|
|
293
|
+
upload?: boolean;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Options for standalone upload (bypassing the useUploadKit pipeline)
|
|
297
|
+
*/
|
|
298
|
+
export interface StandaloneUploadOptions {
|
|
299
|
+
/** MIME type of the data being uploaded. Defaults to 'application/octet-stream'. */
|
|
300
|
+
contentType?: string;
|
|
301
|
+
/** Progress callback (0-100) */
|
|
302
|
+
onProgress?: (percentage: number) => void;
|
|
275
303
|
}
|
|
276
304
|
export interface ImageCompressionOptions {
|
|
277
305
|
maxWidth?: number;
|
|
@@ -316,6 +344,11 @@ export type UploaderEvents<TUploadResult = any> = CoreUploaderEvents<TUploadResu
|
|
|
316
344
|
export type PluginContext<TPluginEvents extends Record<string, any> = Record<string, never>> = {
|
|
317
345
|
files: UploadFile[];
|
|
318
346
|
options: UploadOptions;
|
|
347
|
+
/**
|
|
348
|
+
* Storage plugin for uploading derivatives (thumbnails, variants, etc.)
|
|
349
|
+
* Available only when a storage plugin is configured
|
|
350
|
+
*/
|
|
351
|
+
storage?: StoragePlugin<any, any>;
|
|
319
352
|
/**
|
|
320
353
|
* Emit custom plugin events
|
|
321
354
|
* Events are automatically prefixed with the plugin ID
|
|
@@ -405,6 +438,39 @@ export interface StoragePlugin<TUploadResult = any, TPluginEvents extends Record
|
|
|
405
438
|
hooks: StoragePluginHooks<TUploadResult, TPluginEvents>;
|
|
406
439
|
options?: UploadOptions;
|
|
407
440
|
events?: TPluginEvents;
|
|
441
|
+
/**
|
|
442
|
+
* Upload a raw Blob or File directly to storage, bypassing the useUploadKit pipeline.
|
|
443
|
+
*
|
|
444
|
+
* This is a low-level primitive for uploading arbitrary data without going through
|
|
445
|
+
* validation, preprocessing, or processing stages. Useful for:
|
|
446
|
+
* - Uploading edited/cropped images
|
|
447
|
+
* - Uploading thumbnails separately
|
|
448
|
+
* - Any scenario where you have a Blob and just need it in storage
|
|
449
|
+
*
|
|
450
|
+
* The `storageKey` is treated like a filename — the adapter prepends any configured
|
|
451
|
+
* path prefix (e.g., `options.path`), and the server-side SAS/presigned URL handler
|
|
452
|
+
* may further resolve it (e.g., prepend organization ID).
|
|
453
|
+
*
|
|
454
|
+
* @param data - The Blob or File to upload
|
|
455
|
+
* @param storageKey - Filename or relative path for the file in storage
|
|
456
|
+
* @param options - Optional content type and progress callback
|
|
457
|
+
* @returns The upload result with `url` and resolved `storageKey`
|
|
458
|
+
*
|
|
459
|
+
* @example
|
|
460
|
+
* ```typescript
|
|
461
|
+
* const storage = PluginAzureDataLake({ getSASUrl: ... })
|
|
462
|
+
*
|
|
463
|
+
* // Upload an edited image
|
|
464
|
+
* const result = await storage.upload(croppedBlob, 'edited_photo.jpg', {
|
|
465
|
+
* contentType: 'image/jpeg',
|
|
466
|
+
* })
|
|
467
|
+
* console.log(result.storageKey) // Full resolved path in storage
|
|
468
|
+
* ```
|
|
469
|
+
*/
|
|
470
|
+
upload: (data: Blob | File, storageKey: string, options?: StandaloneUploadOptions) => Promise<TUploadResult & {
|
|
471
|
+
url: string;
|
|
472
|
+
storageKey: string;
|
|
473
|
+
}>;
|
|
408
474
|
}
|
|
409
475
|
/**
|
|
410
476
|
* Base plugin interface (for internal use - supports both types)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PluginContext, UploadFile, FileError, UploadOptions, InitialFileInput } from "./types.js";
|
|
1
|
+
import type { PluginContext, UploadFile, FileError, UploadOptions, InitialFileInput, StoragePlugin } from "./types.js";
|
|
2
2
|
import type { Emitter } from "mitt";
|
|
3
3
|
/**
|
|
4
4
|
* Get file extension from filename
|
|
@@ -7,7 +7,7 @@ export declare function getExtension(fullFileName: string): string;
|
|
|
7
7
|
/**
|
|
8
8
|
* Create a plugin context object with consistent structure
|
|
9
9
|
*/
|
|
10
|
-
export declare function createPluginContext<TPluginEvents extends Record<string, any> = Record<string, never>>(pluginId: string, files: UploadFile[], options: UploadOptions, emitter: Emitter<any>): PluginContext<TPluginEvents>;
|
|
10
|
+
export declare function createPluginContext<TPluginEvents extends Record<string, any> = Record<string, never>>(pluginId: string, files: UploadFile[], options: UploadOptions, emitter: Emitter<any>, storage?: StoragePlugin<any, any>): PluginContext<TPluginEvents>;
|
|
11
11
|
/**
|
|
12
12
|
* Create a consistent file error object
|
|
13
13
|
*/
|
|
@@ -19,6 +19,16 @@ export declare function calculateThumbnailDimensions(originalWidth: number, orig
|
|
|
19
19
|
width: number;
|
|
20
20
|
height: number;
|
|
21
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* Convert a base64-encoded data URL (e.g., from canvas.toDataURL) to a Blob.
|
|
24
|
+
* Only supports base64-encoded data URLs (`;base64,` format).
|
|
25
|
+
*/
|
|
26
|
+
export declare function dataUrlToBlob(dataUrl: string): Blob;
|
|
27
|
+
/**
|
|
28
|
+
* Derive a thumbnail storage key from a file ID by appending '_thumb' before the extension
|
|
29
|
+
* @example "1738345678901-abc123.jpg" → "1738345678901-abc123_thumb.jpg"
|
|
30
|
+
*/
|
|
31
|
+
export declare function deriveThumbnailKey(fileId: string): string;
|
|
22
32
|
/**
|
|
23
33
|
* Cleanup object URLs to prevent memory leaks
|
|
24
34
|
* @param urlMap Map of file IDs to object URLs
|
|
@@ -6,10 +6,11 @@ export function getExtension(fullFileName) {
|
|
|
6
6
|
}
|
|
7
7
|
return fullFileName.slice(lastDot + 1).toLocaleLowerCase();
|
|
8
8
|
}
|
|
9
|
-
export function createPluginContext(pluginId, files, options, emitter) {
|
|
9
|
+
export function createPluginContext(pluginId, files, options, emitter, storage) {
|
|
10
10
|
return {
|
|
11
11
|
files,
|
|
12
12
|
options,
|
|
13
|
+
storage,
|
|
13
14
|
emit: (event, payload) => {
|
|
14
15
|
const prefixedEvent = `${pluginId}:${String(event)}`;
|
|
15
16
|
emitter.emit(prefixedEvent, payload);
|
|
@@ -37,6 +38,24 @@ export function calculateThumbnailDimensions(originalWidth, originalHeight, maxW
|
|
|
37
38
|
}
|
|
38
39
|
return { width, height };
|
|
39
40
|
}
|
|
41
|
+
export function dataUrlToBlob(dataUrl) {
|
|
42
|
+
if (!dataUrl.includes(";base64,")) {
|
|
43
|
+
throw new Error("dataUrlToBlob only supports base64-encoded data URLs");
|
|
44
|
+
}
|
|
45
|
+
const [header, base64] = dataUrl.split(",");
|
|
46
|
+
const mimeType = header.match(/:(.*?);/)?.[1] ?? "image/jpeg";
|
|
47
|
+
const binary = atob(base64);
|
|
48
|
+
const bytes = new Uint8Array(binary.length);
|
|
49
|
+
for (let i = 0; i < binary.length; i++) {
|
|
50
|
+
bytes[i] = binary.charCodeAt(i);
|
|
51
|
+
}
|
|
52
|
+
return new Blob([bytes], { type: mimeType });
|
|
53
|
+
}
|
|
54
|
+
export function deriveThumbnailKey(fileId) {
|
|
55
|
+
const lastDot = fileId.lastIndexOf(".");
|
|
56
|
+
if (lastDot === -1) return `${fileId}_thumb`;
|
|
57
|
+
return `${fileId.slice(0, lastDot)}_thumb${fileId.slice(lastDot)}`;
|
|
58
|
+
}
|
|
40
59
|
export function cleanupObjectURLs(urlMap, fileId) {
|
|
41
60
|
if (fileId) {
|
|
42
61
|
const url = urlMap.get(fileId);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-upload-kit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.25",
|
|
4
4
|
"description": "A powerful, plugin-based file upload manager for Nuxt applications",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "https://github.com/genu/nuxt-upload-kit.git",
|
|
@@ -50,20 +50,20 @@
|
|
|
50
50
|
"docs:dev": "nuxt dev docs --extends docus"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"mitt": "
|
|
53
|
+
"mitt": "3.0.1"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@aws-sdk/client-s3": "3.
|
|
57
|
-
"@aws-sdk/lib-storage": "3.
|
|
58
|
-
"@azure/storage-file-datalake": "
|
|
56
|
+
"@aws-sdk/client-s3": "3.989.0",
|
|
57
|
+
"@aws-sdk/lib-storage": "3.989.0",
|
|
58
|
+
"@azure/storage-file-datalake": "12.29.0",
|
|
59
59
|
"@ffmpeg/ffmpeg": "0.12.15",
|
|
60
60
|
"@ffmpeg/util": "0.12.2",
|
|
61
|
-
"@nuxt/devtools": "
|
|
62
|
-
"@nuxt/eslint-config": "
|
|
61
|
+
"@nuxt/devtools": "3.2.1",
|
|
62
|
+
"@nuxt/eslint-config": "1.15.1",
|
|
63
63
|
"@nuxt/kit": "4.3.1",
|
|
64
|
-
"@nuxt/module-builder": "
|
|
64
|
+
"@nuxt/module-builder": "1.0.2",
|
|
65
65
|
"@nuxt/schema": "4.3.1",
|
|
66
|
-
"@nuxt/test-utils": "
|
|
66
|
+
"@nuxt/test-utils": "4.0.0",
|
|
67
67
|
"@types/node": "latest",
|
|
68
68
|
"@vitejs/plugin-vue": "6.0.4",
|
|
69
69
|
"@vitest/coverage-v8": "4.0.18",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"eslint-config-prettier": "10.1.8",
|
|
72
72
|
"eslint-plugin-prettier": "5.5.5",
|
|
73
73
|
"firebase": "12.9.0",
|
|
74
|
-
"happy-dom": "20.
|
|
74
|
+
"happy-dom": "20.6.1",
|
|
75
75
|
"nuxt": "4.3.1",
|
|
76
76
|
"prettier": "3.8.1",
|
|
77
77
|
"typescript": "5.9.3",
|
|
@@ -100,5 +100,5 @@
|
|
|
100
100
|
"optional": true
|
|
101
101
|
}
|
|
102
102
|
},
|
|
103
|
-
"packageManager": "pnpm@10.29.
|
|
103
|
+
"packageManager": "pnpm@10.29.3"
|
|
104
104
|
}
|