@useupup/core 3.3.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 (118) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +8 -0
  3. package/README.md +75 -0
  4. package/dist/browser-SXR426OQ.cjs +10 -0
  5. package/dist/browser-WD6T5ABJ.js +1 -0
  6. package/dist/chunk-2H5ICKFT.cjs +122 -0
  7. package/dist/chunk-6HF3I2JS.cjs +39 -0
  8. package/dist/chunk-6S5DQDQH.js +212 -0
  9. package/dist/chunk-BMQC27OE.cjs +92 -0
  10. package/dist/chunk-BSGQGINR.cjs +219 -0
  11. package/dist/chunk-CPKZ2CXD.cjs +179 -0
  12. package/dist/chunk-DTKDIMKT.cjs +573 -0
  13. package/dist/chunk-DYE5XJ6Z.cjs +2134 -0
  14. package/dist/chunk-E3ZCNOXG.cjs +74 -0
  15. package/dist/chunk-FEQY2WYY.cjs +2377 -0
  16. package/dist/chunk-FMURBCZ7.js +120 -0
  17. package/dist/chunk-FYQQRULL.js +37 -0
  18. package/dist/chunk-GE4LIVXP.js +133 -0
  19. package/dist/chunk-HFR5HZJZ.js +56 -0
  20. package/dist/chunk-I7ULPCA2.js +72 -0
  21. package/dist/chunk-MHYXDLZR.js +569 -0
  22. package/dist/chunk-N2SLHVAW.cjs +61 -0
  23. package/dist/chunk-OOPDEOTM.js +169 -0
  24. package/dist/chunk-PMBR3OUW.js +2359 -0
  25. package/dist/chunk-QK7HZIVY.cjs +144 -0
  26. package/dist/chunk-T2AQHY7V.cjs +59 -0
  27. package/dist/chunk-TRCP5FUR.js +90 -0
  28. package/dist/chunk-U7KL5M2H.cjs +374 -0
  29. package/dist/chunk-UXNPM54W.js +2108 -0
  30. package/dist/chunk-VV6QCQLL.js +365 -0
  31. package/dist/chunk-ZMS2HXLB.js +56 -0
  32. package/dist/context-shapes-123dd3b6.d.cts +207 -0
  33. package/dist/context-shapes-27b24c8f.d.ts +207 -0
  34. package/dist/contracts-pipeline-cf177270.d.cts +78 -0
  35. package/dist/contracts-pipeline-cf177270.d.ts +78 -0
  36. package/dist/contracts-strategies-378a16b7.d.cts +168 -0
  37. package/dist/contracts-strategies-378a16b7.d.ts +168 -0
  38. package/dist/contracts.cjs +181 -0
  39. package/dist/contracts.d.cts +11 -0
  40. package/dist/contracts.d.ts +11 -0
  41. package/dist/contracts.js +4 -0
  42. package/dist/core-141335ac.d.ts +651 -0
  43. package/dist/core-bea2ceca.d.cts +651 -0
  44. package/dist/create-worker-provider-AA5SRII6.js +58 -0
  45. package/dist/create-worker-provider-KJNUSSTW.cjs +60 -0
  46. package/dist/eligibility-ONLNJ6FB.cjs +10 -0
  47. package/dist/eligibility-ULFC3E4G.js +8 -0
  48. package/dist/error-code-map-9c44a425.d.ts +62 -0
  49. package/dist/error-code-map-dd5becfa.d.cts +62 -0
  50. package/dist/i18n/index.cjs +90 -0
  51. package/dist/i18n/index.d.cts +3 -0
  52. package/dist/i18n/index.d.ts +3 -0
  53. package/dist/i18n/index.js +1 -0
  54. package/dist/index.cjs +1770 -0
  55. package/dist/index.d.cts +280 -0
  56. package/dist/index.d.ts +280 -0
  57. package/dist/index.js +1589 -0
  58. package/dist/internal.cjs +2407 -0
  59. package/dist/internal.d.cts +595 -0
  60. package/dist/internal.d.ts +595 -0
  61. package/dist/internal.js +2275 -0
  62. package/dist/pipeline/index.cjs +10 -0
  63. package/dist/pipeline/index.d.cts +11 -0
  64. package/dist/pipeline/index.d.ts +11 -0
  65. package/dist/pipeline/index.js +1 -0
  66. package/dist/pipeline-worker.cjs +199 -0
  67. package/dist/pipeline-worker.d.cts +2 -0
  68. package/dist/pipeline-worker.d.ts +2 -0
  69. package/dist/pipeline-worker.js +197 -0
  70. package/dist/resolve-locale-81feef21.d.ts +20 -0
  71. package/dist/resolve-locale-9cb63600.d.cts +20 -0
  72. package/dist/resolve-theme-01758105.d.ts +53 -0
  73. package/dist/resolve-theme-66cf8d98.d.cts +53 -0
  74. package/dist/server-mode-drive-controller-b5f8ee12.d.cts +180 -0
  75. package/dist/server-mode-drive-controller-b5f8ee12.d.ts +180 -0
  76. package/dist/steps/compress.cjs +66 -0
  77. package/dist/steps/compress.d.cts +10 -0
  78. package/dist/steps/compress.d.ts +10 -0
  79. package/dist/steps/compress.js +64 -0
  80. package/dist/steps/exif.cjs +44 -0
  81. package/dist/steps/exif.d.cts +5 -0
  82. package/dist/steps/exif.d.ts +5 -0
  83. package/dist/steps/exif.js +42 -0
  84. package/dist/steps/hash.cjs +44 -0
  85. package/dist/steps/hash.d.cts +5 -0
  86. package/dist/steps/hash.d.ts +5 -0
  87. package/dist/steps/hash.js +42 -0
  88. package/dist/steps/heic.cjs +59 -0
  89. package/dist/steps/heic.d.cts +5 -0
  90. package/dist/steps/heic.d.ts +5 -0
  91. package/dist/steps/heic.js +57 -0
  92. package/dist/steps/thumbnail.cjs +54 -0
  93. package/dist/steps/thumbnail.d.cts +10 -0
  94. package/dist/steps/thumbnail.d.ts +10 -0
  95. package/dist/steps/thumbnail.js +52 -0
  96. package/dist/strategies/index.cjs +82 -0
  97. package/dist/strategies/index.d.cts +187 -0
  98. package/dist/strategies/index.d.ts +187 -0
  99. package/dist/strategies/index.js +60 -0
  100. package/dist/strategies/tus-upload.cjs +14 -0
  101. package/dist/strategies/tus-upload.d.cts +15 -0
  102. package/dist/strategies/tus-upload.d.ts +15 -0
  103. package/dist/strategies/tus-upload.js +5 -0
  104. package/dist/theme/index.cjs +38 -0
  105. package/dist/theme/index.d.cts +3 -0
  106. package/dist/theme/index.d.ts +3 -0
  107. package/dist/theme/index.js +1 -0
  108. package/dist/theme-store-2e56a674.d.cts +39 -0
  109. package/dist/theme-store-f13e0315.d.ts +39 -0
  110. package/dist/token-endpoint-5fdb4a35.d.ts +20 -0
  111. package/dist/token-endpoint-a7d15ab6.d.cts +20 -0
  112. package/dist/ui-translations-c5d00392.d.cts +455 -0
  113. package/dist/ui-translations-c5d00392.d.ts +455 -0
  114. package/dist/uploader-props-72242002.d.ts +340 -0
  115. package/dist/uploader-props-7f956e60.d.cts +340 -0
  116. package/dist/vars-d3421f6c.d.cts +240 -0
  117. package/dist/vars-d3421f6c.d.ts +240 -0
  118. package/package.json +182 -0
@@ -0,0 +1,651 @@
1
+ import { a as UploadFile, c as UploadStatus, F as FileSource, P as PipelineStep } from './contracts-pipeline-cf177270.cjs';
2
+ import { h as UploadResult, M as MaxFileSizeObject, R as ResumableUploadOptions } from './contracts-strategies-378a16b7.cjs';
3
+ import { L as LocaleBundle, a as UpupLocaleCode } from './ui-translations-c5d00392.cjs';
4
+
5
+ type ImageEditorOptions = {
6
+ enabled?: boolean;
7
+ display?: 'inline' | 'modal';
8
+ autoOpen?: 'never' | 'single' | 'always';
9
+ output?: {
10
+ mimeType?: string;
11
+ quality?: number;
12
+ fileName?: (original: File) => string;
13
+ };
14
+ tabs?: ('Adjust' | 'Annotate' | 'Filters' | 'Finetune' | 'Resize' | 'Watermark')[];
15
+ tools?: ('Crop' | 'Rotate' | 'Flip' | 'Brightness' | 'Contrast' | 'HSV' | 'Blur' | 'Text' | 'Line' | 'Rect' | 'Ellipse' | 'Polygon' | 'Pen' | 'Arrow' | 'Image')[];
16
+ onOpen?: (file: UploadFile) => void;
17
+ onCancel?: (file: UploadFile) => void;
18
+ onSave?: (editedFile: UploadFile, originalFile: UploadFile) => void;
19
+ };
20
+ type ResolvedImageEditorOptions = Required<Pick<ImageEditorOptions, 'enabled' | 'autoOpen' | 'display'>> & Omit<ImageEditorOptions, 'enabled' | 'autoOpen' | 'display'>;
21
+ type ImageCompressionOptions = {
22
+ quality?: number;
23
+ maxWidth?: number;
24
+ maxHeight?: number;
25
+ mimeType?: string;
26
+ convertSize?: number;
27
+ };
28
+ type ThumbnailGeneratorOptions = {
29
+ thumbnailWidth?: number;
30
+ thumbnailHeight?: number;
31
+ thumbnailType?: string;
32
+ waitForThumbnailsBeforeUpload?: boolean;
33
+ };
34
+
35
+ interface CoreEvents {
36
+ 'state-change': {
37
+ status?: UploadStatus;
38
+ error?: Error;
39
+ files?: Map<string, UploadFile>;
40
+ progress?: {
41
+ totalFiles: number;
42
+ completedFiles: number;
43
+ percentage: number;
44
+ };
45
+ };
46
+ 'upload-start': {
47
+ retry?: boolean;
48
+ fileId?: string;
49
+ };
50
+ 'file-upload-start': {
51
+ file: UploadFile;
52
+ };
53
+ 'upload-progress': {
54
+ fileId: string;
55
+ loaded: number;
56
+ total: number;
57
+ };
58
+ 'upload-success': {
59
+ file: UploadFile;
60
+ result: UploadResult;
61
+ };
62
+ 'upload-error': {
63
+ error: Error;
64
+ file?: UploadFile;
65
+ };
66
+ 'upload-all-complete': UploadFile[];
67
+ 'upload-pause': Record<string, never>;
68
+ 'upload-resume': Record<string, never>;
69
+ 'upload-cancel': Record<string, never>;
70
+ 'files-added': UploadFile[];
71
+ 'file-removed': UploadFile;
72
+ 'file-rejected': {
73
+ count: number;
74
+ };
75
+ 'file-replaced': {
76
+ file: UploadFile;
77
+ };
78
+ 'files-cleared': Record<string, never>;
79
+ 'files-set': {
80
+ count: number;
81
+ };
82
+ 'files-reordered': {
83
+ fileIds: string[];
84
+ };
85
+ 'restriction-failed': {
86
+ error: unknown;
87
+ };
88
+ 'plugin-registered': {
89
+ name: string;
90
+ };
91
+ 'options-updated': {
92
+ partial: Partial<CoreOptions>;
93
+ };
94
+ retry: {
95
+ fileId?: string | undefined;
96
+ };
97
+ 'snapshot-restored': {
98
+ count: number;
99
+ status: UploadStatus;
100
+ };
101
+ 'crash-recovery-restored': Record<string, never>;
102
+ destroyed: Record<string, never>;
103
+ done: Record<string, never>;
104
+ 'state-reset': Record<string, never>;
105
+ 'auto-upload': {
106
+ count: number;
107
+ };
108
+ 'connection-online': Record<string, never>;
109
+ 'connection-offline': Record<string, never>;
110
+ 'image-editor-open': {
111
+ file: UploadFile;
112
+ };
113
+ 'image-editor-cancel': {
114
+ file: UploadFile;
115
+ };
116
+ 'image-editor-save': {
117
+ file: UploadFile;
118
+ original: UploadFile;
119
+ };
120
+ 'drag-over': Record<string, never>;
121
+ 'drag-leave': Record<string, never>;
122
+ drop: {
123
+ files: File[];
124
+ };
125
+ 'folder-drop-blocked': {
126
+ acceptedFiles: number;
127
+ };
128
+ paste: {
129
+ files: File[];
130
+ };
131
+ 'pipeline-start': {
132
+ fileId: string;
133
+ steps: string[];
134
+ };
135
+ 'pipeline-step': {
136
+ fileId: string;
137
+ step: string;
138
+ };
139
+ 'pipeline-complete': {
140
+ fileId: string;
141
+ };
142
+ 'pipeline-error': {
143
+ scope: string;
144
+ name: string;
145
+ message: string;
146
+ };
147
+ 'source-click': {
148
+ sourceId: FileSource;
149
+ };
150
+ 'source-view-cancel': {
151
+ sourceId: FileSource | undefined;
152
+ };
153
+ 'browse-files': Record<string, never>;
154
+ 'folder-select': {
155
+ count: number;
156
+ };
157
+ 'url-submit': {
158
+ url: string;
159
+ };
160
+ 'url-fetch': {
161
+ file: File;
162
+ };
163
+ 'url-fetch-cancel': {
164
+ url: string;
165
+ };
166
+ 'camera-capture': {
167
+ dataUrl: string;
168
+ };
169
+ 'camera-confirm': {
170
+ file: File;
171
+ };
172
+ 'file-preview-open': {
173
+ fileId: string;
174
+ fileName: string;
175
+ };
176
+ 'file-preview-close': {
177
+ fileId: string;
178
+ fileName: string;
179
+ };
180
+ }
181
+
182
+ type EventHandler<T = unknown> = (payload: T) => void;
183
+ declare class EventEmitter<TEvents extends object = Record<string, unknown>> {
184
+ private handlers;
185
+ on<K extends string & keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): () => void;
186
+ on(event: string, handler: EventHandler): () => void;
187
+ off(event: string, handler: EventHandler): void;
188
+ emit<K extends string & keyof TEvents>(event: K, payload: TEvents[K]): void;
189
+ emit(event: string, payload?: unknown): void;
190
+ removeAllListeners(event?: string): void;
191
+ }
192
+
193
+ interface UpupPlugin {
194
+ /** Unique name — used for deduplication and debugging */
195
+ name: string;
196
+ /**
197
+ * Called once when the plugin is registered, with core's event bus. The one
198
+ * plugin lifecycle hook (F-607) — a plugin subscribes to core events and
199
+ * emits its own through this emitter. Optional: a plugin that only needs
200
+ * registration (dedup + storage) may omit it.
201
+ */
202
+ init?(emitter: EventEmitter): void;
203
+ }
204
+ type ExtensionMethods = Record<string, (...args: unknown[]) => unknown>;
205
+ declare class PluginManager {
206
+ private plugins;
207
+ private extensions;
208
+ register(plugin: UpupPlugin): void;
209
+ registerExtension(name: string, methods: ExtensionMethods): void;
210
+ getPlugin(name: string): UpupPlugin | undefined;
211
+ getExtension(name: string): ExtensionMethods | undefined;
212
+ getExtensions(): Record<string, ExtensionMethods>;
213
+ destroy(): void;
214
+ }
215
+
216
+ /**
217
+ * @param bytes assign keyword depend on size
218
+ */
219
+ declare const bytesToSize: (bytes: number) => string;
220
+ /**
221
+ * @param size
222
+ * @param unit
223
+ */
224
+ declare const sizeToBytes: (size: number, unit?: "B" | "KB" | "MB" | "GB" | "TB" | "PB" | "EB" | "ZB" | "YB") => number;
225
+ /**
226
+ * @param file
227
+ * @param sizeLimit
228
+ * @param mode
229
+ */
230
+ declare function checkFileSize(file: File, sizeLimit: MaxFileSizeObject | undefined, mode?: 'max' | 'min'): boolean;
231
+ /**
232
+ * Maximum file size (in bytes) for which text-based preview is allowed.
233
+ * Files exceeding this threshold will show a static icon instead of rendering content,
234
+ * preventing the browser from freezing on large text files (e.g. 3MB+ JSON).
235
+ */
236
+ declare const PREVIEW_MAX_TEXT_SIZE: number;
237
+ /**
238
+ * Maximum number of characters to render in the preview portal for text files.
239
+ * Content beyond this limit is truncated with an indicator.
240
+ */
241
+ declare const PREVIEW_TEXT_TRUNCATE_LENGTH = 100000;
242
+ /**
243
+ * Determines whether a file is a text-based file that could be previewed as text.
244
+ */
245
+ declare function fileGetIsText(fileType: string | undefined, fileName?: string): boolean;
246
+ /**
247
+ * Returns true if a text file is small enough to safely preview inline.
248
+ */
249
+ declare function fileCanPreviewText(fileType: string | undefined, fileName: string | undefined, fileSize: number | undefined): boolean;
250
+ declare function fileGetIsImage(fileType?: string): boolean;
251
+ declare function fileGetIsPdf(fileType: string | undefined, fileName?: string): boolean;
252
+ declare function fileGetExtension(fileType: string | undefined, fileName?: string): string;
253
+ declare function fileIs3D(ext: string): boolean;
254
+ type FileProgress = {
255
+ id: string;
256
+ loaded: number;
257
+ total: number;
258
+ };
259
+ type FilesProgressMap = Record<string, FileProgress>;
260
+ declare function searchDriveFiles<T extends {
261
+ name: string;
262
+ }>(files: T[], searchTerm: string, options?: {
263
+ caseSensitive?: boolean;
264
+ exactMatch?: boolean;
265
+ maxResults?: number;
266
+ }): T[];
267
+
268
+ interface GoogleDriveConfig {
269
+ clientId: string;
270
+ apiKey: string;
271
+ appId: string;
272
+ }
273
+ interface OneDriveConfig {
274
+ clientId: string;
275
+ redirectUri?: string;
276
+ }
277
+ interface DropboxConfig {
278
+ clientId: string;
279
+ redirectUri?: string;
280
+ }
281
+ interface BoxConfig {
282
+ clientId: string;
283
+ redirectUri?: string;
284
+ }
285
+ /** Public cloud-drive configuration — identical shape from framework props down to plugins. */
286
+ interface CloudDrivesConfig {
287
+ googleDrive?: GoogleDriveConfig;
288
+ oneDrive?: OneDriveConfig;
289
+ dropbox?: DropboxConfig;
290
+ box?: BoxConfig;
291
+ }
292
+
293
+ interface FileManagerOptions {
294
+ allowedFileTypes?: string | undefined;
295
+ limit?: number | undefined;
296
+ maxFileSize?: MaxFileSizeObject | undefined;
297
+ minFileSize?: MaxFileSizeObject | undefined;
298
+ maxTotalFileSize?: MaxFileSizeObject | undefined;
299
+ contentDeduplication?: boolean | undefined;
300
+ onBeforeFileAdded?: ((file: File) => boolean | File | undefined | Promise<boolean | File | undefined>) | undefined;
301
+ }
302
+ declare class FileManager {
303
+ private files;
304
+ private options;
305
+ constructor(options: FileManagerOptions);
306
+ updateOptions(options: Partial<FileManagerOptions>): void;
307
+ getFiles(): ReadonlyMap<string, UploadFile>;
308
+ /**
309
+ * Immutable file-status transition: produce a NEW UploadFile carrying the patch,
310
+ * store and return it. FileManager is the sole writer of a file's status/key/metadata
311
+ * (F-144), and the new reference lets the orchestrator's ref-diff projection track the
312
+ * transition (F-145).
313
+ *
314
+ * Constraint: object-spread (`{ ...prev }`) would strip File's blob data and methods —
315
+ * they live in internal slots / on the prototype, not as own-enumerable props — leaving
316
+ * a plain object that breaks `xhr.send(file)` in the direct-upload strategy. So we
317
+ * re-wrap the same backing bytes into a fresh File (a view, not a copy) and copy the
318
+ * UploadFile fields onto it — mirroring `cloneUploadFile` (steps/image-utils.ts). Do
319
+ * NOT "simplify" this back to a spread.
320
+ */
321
+ updateFile(id: string, patch: Partial<UploadFile>): UploadFile | undefined;
322
+ private validateFile;
323
+ private collectAcceptedFiles;
324
+ private deduplicateByContent;
325
+ private assertBatchFits;
326
+ addFiles(nativeFiles: File[]): Promise<UploadFile[]>;
327
+ removeFile(id: string): UploadFile | undefined;
328
+ replaceFile(id: string, file: File | UploadFile): UploadFile;
329
+ removeAll(): void;
330
+ /** Bulk-apply pipeline-produced files (already UploadFile with status/key set). */
331
+ applyProcessed(files: UploadFile[]): void;
332
+ /** Re-instate a prior snapshot: clear and repopulate from entries. */
333
+ restore(entries: [string, UploadFile][]): void;
334
+ setFiles(nativeFiles: File[]): Promise<UploadFile[]>;
335
+ reorderFiles(fileIds: string[]): void;
336
+ }
337
+
338
+ interface PersistentStorage {
339
+ get(key: string): Promise<unknown>;
340
+ set(key: string, value: unknown): Promise<void>;
341
+ delete(key: string): Promise<void>;
342
+ }
343
+ declare class CrashRecoveryManager {
344
+ private storage;
345
+ constructor(storage: PersistentStorage);
346
+ save(snapshot: unknown): Promise<void>;
347
+ restore(): Promise<unknown>;
348
+ clear(): Promise<void>;
349
+ }
350
+ /**
351
+ * IndexedDB-based storage for browser environments.
352
+ * Falls back gracefully when IndexedDB is unavailable (SSR, privacy mode).
353
+ */
354
+ declare class IndexedDBStorage implements PersistentStorage {
355
+ private dbName;
356
+ private storeName;
357
+ /** ONE cached connection for the storage's lifetime — never closed after
358
+ * an operation. Firefox ties Blob/File handles read from IndexedDB to
359
+ * the connection they were read over: with the old open-per-operation /
360
+ * close-on-complete lifecycle, the File revived by the crash-recovery
361
+ * restore lost its backing store shortly after the restore's transaction
362
+ * closed, and mid-resume slice reads rejected with AbortError ("The
363
+ * operation was aborted") — a Firefox-only reload-resume stall reproduced
364
+ * against both MinIO and Backblaze B2 (Chromium materializes IndexedDB
365
+ * blobs independently of the connection and never failed). The cache
366
+ * still yields: `versionchange` (a deleteDatabase/upgrade elsewhere)
367
+ * closes and drops it so the other context is never blocked, and a
368
+ * browser-initiated `close` drops it so the next operation reopens. */
369
+ private dbPromise;
370
+ constructor(dbName?: string);
371
+ private getDB;
372
+ /** Close and release the cached connection. Safe at any time — the next
373
+ * operation reopens. `UpupCore.destroy()` calls this so an unmounted
374
+ * uploader doesn't keep the database held open (pending transactions
375
+ * still drain first per the IndexedDB spec, so a queued snapshot write
376
+ * is never cut off mid-transaction). */
377
+ close(): void;
378
+ get(key: string): Promise<unknown>;
379
+ set(key: string, value: unknown): Promise<void>;
380
+ delete(key: string): Promise<void>;
381
+ }
382
+
383
+ interface UpupCorsConfig {
384
+ dangerouslyAutoConfigure?: boolean;
385
+ allowedOrigins: string[];
386
+ allowedMethods?: string[];
387
+ allowedHeaders?: string[];
388
+ maxAgeSeconds?: number;
389
+ }
390
+ interface CrashRecoveryOptions {
391
+ storage?: PersistentStorage;
392
+ }
393
+ interface CoreOptions extends FileManagerOptions {
394
+ uploadEndpoint?: string | undefined;
395
+ serverUrl?: string | undefined;
396
+ provider?: string | undefined;
397
+ mode?: 'client' | 'server' | undefined;
398
+ plugins?: UpupPlugin[] | undefined;
399
+ pipeline?: PipelineStep[] | undefined;
400
+ resumable?: ResumableUploadOptions | undefined;
401
+ heicConversion?: boolean | undefined;
402
+ stripExifData?: boolean | undefined;
403
+ imageCompression?: boolean | object | undefined;
404
+ thumbnailGenerator?: boolean | object | undefined;
405
+ checksumVerification?: boolean | undefined;
406
+ /**
407
+ * Web Worker offload for the file pipeline (hash/heic/exif/thumbnail/compress).
408
+ * Unset/`true` = auto (workers used when supported, transparent main-thread
409
+ * fallback otherwise). `false` = force the main thread.
410
+ */
411
+ webWorker?: boolean | undefined;
412
+ /**
413
+ * Web-worker task timeout in ms. Default 30000. On timeout the task falls
414
+ * back to main-thread processing (it never fails the file).
415
+ */
416
+ workerTimeoutMs?: number | undefined;
417
+ maxRetries?: number | undefined;
418
+ maxConcurrentUploads?: number | undefined;
419
+ autoUpload?: boolean | undefined;
420
+ /**
421
+ * React to browser connectivity: going offline mid-upload pauses the run
422
+ * (so multipart sessions persist instead of burning retries against a dead
423
+ * network), and coming back online resumes it — only when the pause was
424
+ * offline-initiated, never overriding a pause the user chose. Default on;
425
+ * `false` restores the fail-and-retry behavior. No-op outside a browser.
426
+ */
427
+ networkAware?: boolean | undefined;
428
+ fastAbortThreshold?: number | undefined;
429
+ isSuccessfulCall?: ((response: {
430
+ status: number;
431
+ headers: Record<string, string>;
432
+ body: unknown;
433
+ }) => boolean | Promise<boolean>) | undefined;
434
+ crashRecovery?: boolean | CrashRecoveryOptions | undefined;
435
+ onError?: ((error: string | Error) => void) | undefined;
436
+ metadata?: Record<string, unknown> | undefined;
437
+ cors?: UpupCorsConfig | undefined;
438
+ /**
439
+ * i18n configuration. Accepts either:
440
+ * - a full LocaleBundle (`import { enUS } from './contracts'`) — also
441
+ * drives the file-pipeline translator (`context.t` inside pipeline
442
+ * steps), not just the UI translator.
443
+ * - a BCP 47 locale code string (e.g. `'fr-FR'`) — resolves to lang/dir
444
+ * only until a locale registry exists; consumers are responsible for
445
+ * resolving codes to bundles via `i18n.loadLocale`.
446
+ */
447
+ locale?: LocaleBundle | UpupLocaleCode | undefined;
448
+ cloudDrives?: CloudDrivesConfig | undefined;
449
+ }
450
+ type ValidationResult = {
451
+ file: File;
452
+ valid: boolean;
453
+ errors: Array<{
454
+ code: string;
455
+ message: string;
456
+ }>;
457
+ };
458
+ type UploadOptions = {
459
+ checksumVerification?: boolean;
460
+ imageCompression?: boolean | object;
461
+ heicConversion?: boolean;
462
+ stripExifData?: boolean;
463
+ maxRetries?: number;
464
+ metadata?: Record<string, string>;
465
+ };
466
+
467
+ declare class UpupCore {
468
+ private emitter;
469
+ private pluginManager;
470
+ private fileManager;
471
+ private pipelineEngine;
472
+ private uploadManager;
473
+ private _status;
474
+ private _error;
475
+ private crashRecovery;
476
+ private crashRecoveryStorage;
477
+ private crashRecoveryUnsubscribe;
478
+ /** Every crash-recovery storage write flows through this one promise chain.
479
+ * Blob snapshots of large files make IndexedDB puts slow; fire-and-forget
480
+ * save/clear calls complete out of order, so a save started before
481
+ * completion can land after the completion clear and resurrect a finished
482
+ * upload as a resumable one. FIFO ordering makes the last requested op the
483
+ * last applied op. */
484
+ private crashRecoveryChain;
485
+ /** True while a snapshot sync is queued but not yet run. Progress ticks
486
+ * arrive far faster than a large snapshot writes; coalescing them into the
487
+ * one queued sync (which reads state at write time) keeps it to at most
488
+ * one write in flight plus one pending, instead of N stacked blob puts. */
489
+ private crashRecoverySyncQueued;
490
+ private fileOverrides;
491
+ private pauseRequested;
492
+ private cancelRequested;
493
+ private destroyed;
494
+ /** True only while the CURRENT pause was made by the offline handler —
495
+ * the one case `online` may resume. A pause the user chose stays theirs. */
496
+ private offlinePausedRun;
497
+ private detachNetworkListeners;
498
+ private activeRun;
499
+ private workerProvider;
500
+ options: CoreOptions;
501
+ constructor(options: CoreOptions);
502
+ /** Connectivity reactions (`networkAware`, default on): `offline` pauses
503
+ * an active run — with `persist` on, that keeps the multipart session
504
+ * alive instead of burning whole-run retries against a dead network —
505
+ * and `online` resumes it, but ONLY when this handler made the pause.
506
+ * SSR/node-safe: without a window this installs nothing. */
507
+ private installNetworkAwareness;
508
+ /** The one projection of CoreOptions the FileManager consumes — construction
509
+ * and updateOptions() must stay in lockstep, so both call this. */
510
+ private fileManagerOptions;
511
+ get files(): ReadonlyMap<string, UploadFile>;
512
+ get status(): UploadStatus;
513
+ get error(): Error | null;
514
+ get progress(): {
515
+ totalFiles: number;
516
+ completedFiles: number;
517
+ percentage: number;
518
+ };
519
+ /**
520
+ * Crash-recovery persistence is best-effort by design — a failed save/clear
521
+ * must never break an upload. But full silence hides a dead durability
522
+ * opt-in (F-734): surface failures dev-only, matching the worker-fallback
523
+ * convention in maybeCreateWorkerProvider().
524
+ */
525
+ private warnCrashRecoveryFailure;
526
+ private configureCrashRecovery;
527
+ /** Queue a snapshot write that reads files/status at WRITE time, not at
528
+ * event time — so the write that runs last always reflects the state that
529
+ * came last, and a completion observed while a save is queued turns that
530
+ * queued write into the clear instead of racing it. */
531
+ private queueCrashRecoverySync;
532
+ /** Queue an unconditional clear behind any in-flight snapshot write. The
533
+ * default manager is captured at call time so a clear requested before
534
+ * disable/destroy still applies after the field is nulled. */
535
+ private queueCrashRecoveryClear;
536
+ private enqueueCrashRecoveryOp;
537
+ private disableCrashRecovery;
538
+ use(plugin: UpupPlugin): this;
539
+ registerExtension(name: string, methods: ExtensionMethods): void;
540
+ getPlugin(name: string): UpupPlugin | undefined;
541
+ getExtension(name: string): ExtensionMethods | undefined;
542
+ get ext(): Record<string, ExtensionMethods>;
543
+ addFiles(files: File[], overrides?: Partial<UploadOptions>): Promise<void>;
544
+ /**
545
+ * Discard the persisted multipart sessions of files the user just threw
546
+ * away (cancel / removeFile / removeAll), aborting them server-side on the
547
+ * way out. With `resumable.persist` on, a failed or cancelled upload
548
+ * deliberately keeps its server-side parts alive for a later resume — so
549
+ * an explicit discard is the ONE place that has to say "no, really, drop
550
+ * it", or the user pays storage for parts nothing will ever finish.
551
+ *
552
+ * Fire-and-forget and fully swallowed: cancelling must never throw or wait.
553
+ */
554
+ private discardPersistedMultipartSessions;
555
+ removeFile(id: string): void;
556
+ removeAll(): void;
557
+ setFiles(files: File[]): Promise<void>;
558
+ /** Update options after construction (e.g. when React props change). */
559
+ updateOptions(partial: Partial<CoreOptions>): void;
560
+ reorderFiles(fileIds: string[]): void;
561
+ private maybeCreateWorkerProvider;
562
+ private hasUploadTarget;
563
+ private createUploadManager;
564
+ private markFilesReady;
565
+ private updatePendingFileStatuses;
566
+ private markUnsuccessfulFilesFailed;
567
+ private uploadFiles;
568
+ validateFiles(files: File[]): Promise<ValidationResult[]>;
569
+ upload(): Promise<UploadFile[]>;
570
+ private resetRunFlags;
571
+ private runUpload;
572
+ /**
573
+ * The single terminal-failure path shared by all three run flavors
574
+ * (runUpload / runRetry / resume). They previously diverged (F-729): only
575
+ * runUpload marked leftover files FAILED, and resume never invoked
576
+ * options.onError — a retry/resume failure looked different to consumers
577
+ * than the identical first-run failure for no reason.
578
+ */
579
+ private terminalRunFailure;
580
+ replaceFile(id: string, file: File | UploadFile): void;
581
+ /**
582
+ * Pause in-flight uploads by aborting the current abort controller.
583
+ * Note: This cancels active HTTP requests. Resume will re-upload
584
+ * files that were in progress — true pause/resume of partial uploads
585
+ * requires multipart upload support.
586
+ */
587
+ pause(): void;
588
+ /**
589
+ * Resume uploads after a pause. Re-uploads files that did not
590
+ * complete successfully (those without a `key` set).
591
+ */
592
+ resume(): void;
593
+ cancel(): void;
594
+ retry(fileId?: string): Promise<UploadFile[]>;
595
+ private runRetry;
596
+ /**
597
+ * Bare event names are the typed CoreEvents catalog and nothing else —
598
+ * the untyped string overload is gone (F-723), so an unknown bare event is
599
+ * now a compile error at the emit/subscribe site. Namespaced drive-plugin
600
+ * events ('<provider>:<event>', e.g. 'google-drive:files-loaded') are
601
+ * dynamic by design — plugins emit them through core's bus (see use()) —
602
+ * and keep a template-literal passthrough.
603
+ */
604
+ on<K extends keyof CoreEvents>(event: K, handler: (payload: CoreEvents[K]) => void): () => void;
605
+ on(event: `${string}:${string}`, handler: (payload: unknown) => void): () => void;
606
+ off<K extends keyof CoreEvents>(event: K, handler: (payload: CoreEvents[K]) => void): void;
607
+ off(event: `${string}:${string}`, handler: (payload: unknown) => void): void;
608
+ emit<K extends keyof CoreEvents>(event: K, payload: CoreEvents[K]): void;
609
+ emit(event: `${string}:${string}`, data?: unknown): void;
610
+ getSnapshot(): {
611
+ files: [string, UploadFile][];
612
+ status: UploadStatus;
613
+ };
614
+ restore(snapshot: {
615
+ files: [string, UploadFile][];
616
+ status: UploadStatus;
617
+ }): void;
618
+ restoreFromCrashRecovery(): Promise<boolean>;
619
+ /** `resumable.autoResume` continues a crash-restored upload without the
620
+ * explicit Resume click. Off by default on purpose: closing a tab is an
621
+ * ambiguous signal — as often "cancel" as "oops" — so silently resuming
622
+ * a transfer the user may have meant to kill is an integrator's call,
623
+ * never the library's. Deferred a tick so the host finishes mounting
624
+ * (the same guard autoUpload's timer carries, F-148), and re-checked at
625
+ * fire time: the user may have discarded the restore in between. */
626
+ private maybeScheduleAutoResume;
627
+ /** A restored PAUSED file rendered "0 B of N" even when most of it was
628
+ * already in storage — the persisted multipart session knows the real
629
+ * offset, but nothing replayed it into the progress pipeline until the
630
+ * user actually hit resume. Emit it here so the restored UI opens at the
631
+ * byte count the resume will continue from. Same session gates as
632
+ * tryResume (scope), minus the server round-trip: this is display-only
633
+ * and must not spend a request; the authoritative recheck still happens
634
+ * on resume. */
635
+ /** A finished multipart upload can die in the window between its
636
+ * synchronous session removal and the asynchronous IndexedDB snapshot
637
+ * clear — the next visit then restores a file the server already
638
+ * assembled, offering a Resume that would re-upload all of it. The
639
+ * session store is the tiebreaker: init writes the session synchronously
640
+ * before the first byte moves and completion removes it synchronously,
641
+ * so an UPLOADING-status file of multipart size with no session is a
642
+ * stale snapshot, not a crashed upload. PROCESSING files never had a
643
+ * session and stay restorable; so does everything below the multipart
644
+ * threshold or outside persist mode. */
645
+ private isStaleMultipartRestore;
646
+ private seedRestoredProgress;
647
+ clearCrashRecovery(): Promise<void>;
648
+ destroy(): void;
649
+ }
650
+
651
+ export { type BoxConfig as B, type CoreEvents as C, type DropboxConfig as D, EventEmitter as E, type FilesProgressMap as F, type GoogleDriveConfig as G, type ImageEditorOptions as I, type OneDriveConfig as O, PluginManager as P, type ResolvedImageEditorOptions as R, type ThumbnailGeneratorOptions as T, UpupCore as U, type ValidationResult as V, type ImageCompressionOptions as a, type CloudDrivesConfig as b, type UpupPlugin as c, type CoreOptions as d, type UploadOptions as e, type UpupCorsConfig as f, type ExtensionMethods as g, type FileProgress as h, FileManager as i, CrashRecoveryManager as j, IndexedDBStorage as k, type PersistentStorage as l, bytesToSize as m, checkFileSize as n, PREVIEW_MAX_TEXT_SIZE as o, PREVIEW_TEXT_TRUNCATE_LENGTH as p, fileGetIsImage as q, fileGetIsPdf as r, sizeToBytes as s, fileGetIsText as t, fileCanPreviewText as u, fileGetExtension as v, fileIs3D as w, searchDriveFiles as x };