@gentleduck/upload 0.2.6 → 0.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 (136) hide show
  1. package/README.md +170 -193
  2. package/dist/core/index.d.ts +2 -3
  3. package/dist/core/index.js +1 -1
  4. package/dist/core-BVgloTiP.js +10 -0
  5. package/dist/index-DCqyBVcx.d.ts +1441 -0
  6. package/dist/index-DsZHPmJm.d.ts +225 -0
  7. package/dist/index-KROXtLQh.d.ts +281 -0
  8. package/dist/index.d.ts +4 -5
  9. package/dist/index.js +1 -1
  10. package/dist/react/index.d.ts +2 -51
  11. package/dist/react/index.js +1 -1
  12. package/dist/react-euPrDv24.js +1 -0
  13. package/dist/strategies/index.d.ts +2 -56
  14. package/dist/strategies/index.js +1 -1
  15. package/dist/strategies-CUF0s68j.js +1 -0
  16. package/package.json +3 -2
  17. package/src/{__test__ → __tests__}/emitter.test.ts +4 -4
  18. package/src/{__test__ → __tests__}/fingerprint.test.ts +1 -1
  19. package/src/{__test__ → __tests__}/guards.test.ts +15 -5
  20. package/src/__tests__/id.test.ts +67 -0
  21. package/src/__tests__/mime-sniff.test.ts +142 -0
  22. package/src/{__test__ → __tests__}/persistence.test.ts +43 -8
  23. package/src/__tests__/sanitize-filename.test.ts +109 -0
  24. package/src/__tests__/sleep.test.ts +34 -0
  25. package/src/__tests__/static-analysis.test.ts +145 -0
  26. package/src/{__test__ → __tests__}/store-libs.test.ts +57 -3
  27. package/src/__tests__/transport-fetch.test.ts +108 -0
  28. package/src/{__test__ → __tests__}/transport.test.ts +5 -5
  29. package/src/core/__tests__/errors.test.ts +152 -0
  30. package/src/core/client.ts +3 -0
  31. package/src/core/contracts/contracts.types.ts +335 -141
  32. package/src/core/contracts/index.ts +3 -8
  33. package/src/core/contracts/transport/index.ts +3 -2
  34. package/src/core/contracts/transport/transport.fetch.ts +203 -0
  35. package/src/core/contracts/transport/transport.libs.ts +7 -8
  36. package/src/core/contracts/transport/transport.ts +91 -83
  37. package/src/core/contracts/transport/transport.types.ts +71 -35
  38. package/src/core/engine/__tests__/config-nan-bypass.test.ts +40 -0
  39. package/src/core/engine/engine.libs.ts +35 -0
  40. package/src/core/engine/engine.types.ts +367 -241
  41. package/src/core/engine/index.ts +3 -8
  42. package/src/core/engine/reducer.ts +89 -43
  43. package/src/core/engine/store/handlers/add-file.ts +39 -29
  44. package/src/core/engine/store/handlers/cancel.ts +13 -8
  45. package/src/core/engine/store/handlers/clean-up.ts +11 -8
  46. package/src/core/engine/store/handlers/create-intent.ts +82 -27
  47. package/src/core/engine/store/handlers/finalize.ts +30 -13
  48. package/src/core/engine/store/handlers/index.ts +7 -7
  49. package/src/core/engine/store/handlers/pause.ts +8 -6
  50. package/src/core/engine/store/handlers/run-upload.ts +49 -34
  51. package/src/core/engine/store/index.ts +27 -21
  52. package/src/core/engine/store/store.dispatch.ts +10 -8
  53. package/src/core/engine/store/store.libs.ts +184 -41
  54. package/src/core/engine/store/store.runtime.ts +45 -36
  55. package/src/core/engine/store/store.schedule.ts +27 -21
  56. package/src/core/engine/store/store.types.ts +177 -227
  57. package/src/core/engine/validation/__tests__/intent.test.ts +70 -0
  58. package/src/core/engine/validation/file.ts +7 -3
  59. package/src/core/engine/validation/index.ts +1 -0
  60. package/src/core/engine/validation/intent.ts +49 -27
  61. package/src/core/engine/validation/list.ts +14 -15
  62. package/src/core/engine/validation/mime.ts +39 -0
  63. package/src/core/errors.ts +271 -0
  64. package/src/core/index.ts +28 -5
  65. package/src/core/persistence/__tests__/deserialize-nan-bypass.test.ts +100 -0
  66. package/src/core/persistence/__tests__/persistence.test.ts +85 -0
  67. package/src/core/persistence/adapters.indexeddb.ts +9 -3
  68. package/src/core/persistence/adapters.local.ts +9 -3
  69. package/src/core/persistence/adapters.memory.ts +35 -13
  70. package/src/core/persistence/index.ts +5 -5
  71. package/src/core/persistence/persistence.ts +73 -60
  72. package/src/core/persistence/persistence.types.ts +140 -60
  73. package/src/core/utils/__tests__/guards.test.ts +93 -0
  74. package/src/core/utils/__tests__/url-safety.test.ts +112 -0
  75. package/src/core/utils/async.ts +7 -2
  76. package/src/core/utils/constants.ts +3 -9
  77. package/src/core/utils/emitter/emitter.ts +7 -24
  78. package/src/core/utils/emitter/emitter.types.ts +33 -16
  79. package/src/core/utils/emitter/index.ts +2 -74
  80. package/src/core/utils/fingerprint.ts +16 -5
  81. package/src/core/utils/guards.ts +91 -1
  82. package/src/core/utils/hash/__tests__/sha256.test.ts +61 -0
  83. package/src/core/utils/hash/index.ts +126 -0
  84. package/src/core/utils/hash/sha256.ts +179 -0
  85. package/src/core/utils/id.ts +33 -1
  86. package/src/core/utils/index.ts +15 -6
  87. package/src/core/utils/mime-sniff.ts +119 -0
  88. package/src/core/utils/sanitize-filename.ts +85 -0
  89. package/src/core/utils/url-safety.ts +156 -0
  90. package/src/react/__tests__/use-dropzone.test.ts +64 -0
  91. package/src/react/index.ts +5 -2
  92. package/src/react/upload-provider.tsx +68 -53
  93. package/src/react/uploader.types.ts +58 -61
  94. package/src/react/use-dropzone.tsx +226 -0
  95. package/src/react/use-uploader.tsx +98 -91
  96. package/src/strategies/_shared/__tests__/retry.test.ts +120 -0
  97. package/src/strategies/_shared/retry.ts +79 -0
  98. package/src/strategies/index.ts +9 -15
  99. package/src/strategies/multipart/__tests__/multipart.test.ts +229 -0
  100. package/src/strategies/multipart/index.ts +206 -108
  101. package/src/strategies/post/__tests__/post-url-safety.test.ts +119 -0
  102. package/src/strategies/post/index.ts +115 -33
  103. package/src/strategies/put/__tests__/put.test.ts +132 -0
  104. package/src/strategies/put/index.ts +139 -0
  105. package/src/strategies/registry/index.ts +12 -9
  106. package/src/strategies/tus/__tests__/tus.test.ts +159 -0
  107. package/src/strategies/tus/index.ts +211 -0
  108. package/dist/async-DxRWu4le.js +0 -1
  109. package/dist/core-CMkrP9DX.js +0 -2
  110. package/dist/index-C38Jmizu.d.ts +0 -1005
  111. package/dist/strategy.types-gg9ZStRe.d.ts +0 -225
  112. package/src/__test__/effect-pool.test.ts +0 -5
  113. package/src/__test__/id.test.ts +0 -14
  114. package/src/__test__/store-integration.test.ts +0 -5
  115. package/src/core/client/client.ts +0 -50
  116. package/src/core/client/client.types.ts +0 -184
  117. package/src/core/client/config.types.ts +0 -77
  118. package/src/core/client/index.ts +0 -4
  119. package/src/core/client/plugins.types.ts +0 -46
  120. package/src/core/client/retry.types.ts +0 -6
  121. package/src/core/client/uploadClient.ts +0 -19
  122. package/src/core/contracts/backendApi.ts +0 -62
  123. package/src/core/contracts/cursor.types.ts +0 -23
  124. package/src/core/contracts/errors.types.ts +0 -67
  125. package/src/core/contracts/fingerprint.types.ts +0 -18
  126. package/src/core/contracts/intent.types.ts +0 -39
  127. package/src/core/contracts/result.types.ts +0 -11
  128. package/src/core/contracts/strategy.types.ts +0 -45
  129. package/src/core/engine/commands.types.ts +0 -17
  130. package/src/core/engine/event-map.types.ts +0 -45
  131. package/src/core/engine/internal-events.types.ts +0 -202
  132. package/src/core/engine/outcome.types.ts +0 -9
  133. package/src/core/engine/progress.types.ts +0 -15
  134. package/src/core/engine/store/handlers.ts +0 -819
  135. package/src/core/engine/validation.ts +0 -216
  136. /package/src/{__test__ → __tests__}/transport-libs.test.ts +0 -0
@@ -0,0 +1,1441 @@
1
+ //#region src/core/contracts/contracts.types.d.ts
2
+ /**
3
+ * Public contract types grouped under the `Contracts` namespace.
4
+ *
5
+ * Each sub-namespace owns one concern (Intent, Cursor, Result, Validation,
6
+ * Fingerprint, Errors, Strategy, BackendApi).
7
+ * @author wildduck2 <https://github.com/wildduck2>
8
+ */
9
+ declare namespace Contracts {
10
+ namespace Intent {
11
+ /** Base shape for all upload intents. */
12
+ type Base<K extends string = string> = {
13
+ /** Strategy name (discriminant). */strategy: K; /** Unique backend file identifier. */
14
+ fileId: string;
15
+ };
16
+ /** Registry of intent types mapped by strategy name. */
17
+ type Map = Record<string, Base<string>>;
18
+ /** Union of strategy keys for an intent map. */
19
+ type StrategyKey<M extends Map> = keyof M & string;
20
+ /** Union of all intent variants for an intent map. */
21
+ type Any<M extends Map> = M[StrategyKey<M>];
22
+ }
23
+ namespace Cursor {
24
+ /** Registry of cursor payload types mapped by strategy name. */
25
+ type Map<M extends Intent.Map> = Partial<Record<Intent.StrategyKey<M>, unknown>>;
26
+ /** Discriminated union of all cursor variants. */
27
+ type Any<C extends Record<string, unknown>> = { [K in keyof C & string]: {
28
+ /** Strategy name associated with this cursor. */strategy: K; /** The custom strategy-defined state needed to resume the upload. */
29
+ value?: C[K] | undefined;
30
+ } }[keyof C & string];
31
+ }
32
+ namespace Result {
33
+ /** Successful upload payload returned by your backend API's complete endpoint. */
34
+ type Base = {
35
+ /** Unique backend file identifier. */fileId: string; /** Storage key/path or public address of the uploaded file. */
36
+ key: string;
37
+ };
38
+ }
39
+ namespace Validation {
40
+ /** Why a file was rejected during client-side validation. */
41
+ type Rejection = {
42
+ code: 'empty_file';
43
+ } | {
44
+ code: 'file_too_large';
45
+ maxBytes: number;
46
+ size: number;
47
+ } | {
48
+ code: 'type_not_allowed';
49
+ allowed: string[];
50
+ got: string;
51
+ } | {
52
+ code: 'too_many_files';
53
+ max: number;
54
+ } | {
55
+ code: 'mime_mismatch';
56
+ claimed: string;
57
+ sniffed: string;
58
+ } | {
59
+ code: 'filename_rejected';
60
+ reason: 'reserved' | 'too-long' | 'empty' | 'path-sep';
61
+ };
62
+ }
63
+ /** Deterministic identity signature of a file on the client. */
64
+ type FingerprintFile = {
65
+ /** Base name of the file (excluding directory path). */name: string; /** Size of the file in bytes. */
66
+ size: number; /** MIME type of the file. */
67
+ type: string; /** Timestamp when the file was last modified on disk (milliseconds since epoch). */
68
+ lastModified: number; /** Optional pre-computed checksum of the file (e.g. SHA-256 hex). */
69
+ checksum?: string | undefined;
70
+ };
71
+ namespace Errors {
72
+ /** Base schema for upload-related runtime errors. */
73
+ type Base = {
74
+ /** Stable machine-readable error classification. */code: string; /** Human-friendly message suitable for presentation in standard warning elements. */
75
+ message: string; /** Original thrown error or reason context if available. */
76
+ cause?: unknown; /** Flag specifying whether the error recovery system should schedule retries. */
77
+ retryable?: boolean;
78
+ };
79
+ /** Discriminant union of built-in engine failure structures. */
80
+ type BuiltIn = {
81
+ code: 'validation_failed';
82
+ message: string;
83
+ reason: Validation.Rejection;
84
+ retryable?: false;
85
+ } | {
86
+ code: 'strategy_missing';
87
+ message: string;
88
+ strategy: string;
89
+ retryable?: false;
90
+ } | {
91
+ code: 'aborted';
92
+ message: string;
93
+ reason: 'pause' | 'cancel' | 'unknown';
94
+ cause?: unknown;
95
+ retryable?: false;
96
+ } | {
97
+ code: 'network';
98
+ message: string;
99
+ cause?: unknown;
100
+ retryable?: boolean;
101
+ } | {
102
+ code: 'http';
103
+ message: string;
104
+ status: number;
105
+ statusText?: string;
106
+ cause?: unknown;
107
+ retryable?: boolean;
108
+ } | {
109
+ code: 'timeout';
110
+ message: string;
111
+ cause?: unknown;
112
+ retryable?: boolean;
113
+ } | {
114
+ code: 'auth';
115
+ message: string;
116
+ cause?: unknown;
117
+ retryable?: false;
118
+ } | {
119
+ code: 'rate_limit';
120
+ message: string;
121
+ retryAfterMs?: number;
122
+ cause?: unknown;
123
+ retryable?: boolean;
124
+ } | {
125
+ code: 'server';
126
+ message: string;
127
+ serverCode?: string;
128
+ cause?: unknown;
129
+ retryable?: boolean;
130
+ } | {
131
+ code: 'unknown';
132
+ message: string;
133
+ cause?: unknown;
134
+ retryable?: boolean;
135
+ };
136
+ /** The canonical error shape handled by the engine, plugins, and handlers. */
137
+ type Error = BuiltIn | (Base & Record<string, unknown>);
138
+ }
139
+ /** Validation rules applied to files on registration before intents are initiated. */
140
+ type ValidationRules = {
141
+ /** Maximum number of files permitted in a single upload batch. */maxFiles?: number; /** Maximum size in bytes allowed for a single file. */
142
+ maxSizeBytes?: number; /** Minimum size in bytes allowed for a single file. */
143
+ minSizeBytes?: number; /** White-list of allowed MIME types (e.g. `["image/png", "application/pdf"]`). */
144
+ allowedTypes?: string[]; /** White-list of allowed file extension strings (e.g. `["png", "pdf"]`). */
145
+ allowedExtensions?: string[];
146
+ };
147
+ /**
148
+ * Safe, cause-stripped error summary stored in step history and forwarded in API context.
149
+ * The raw `cause` field is omitted because it may contain sensitive server response bodies.
150
+ */
151
+ type StepError = {
152
+ code: string;
153
+ message: string;
154
+ retryable?: boolean;
155
+ };
156
+ /** A single recorded phase transition on an upload item. */
157
+ type UploadStep = {
158
+ /** Phase name when this step was entered. */phase: string; /** Epoch ms when this phase was entered. */
159
+ enteredAt: number; /** Epoch ms when this phase was left. Undefined while still in this phase. */
160
+ leftAt?: number; /** Attempt number at the time of entering this phase. */
161
+ attempt: number; /** Safe error summary if this phase ended in failure. Cause is stripped. */
162
+ error?: StepError | undefined;
163
+ };
164
+ namespace Api {
165
+ /** Context passed to every backend API method alongside the call-specific args. */
166
+ type Context<P extends string = string, M extends Intent.Map = Intent.Map> = {
167
+ /** Client-side identifier for this file item. */localId: string; /** Upload purpose. */
168
+ purpose: P; /** File identity: name, size, MIME type, checksum. Always present. */
169
+ fingerprint: FingerprintFile; /** Which attempt this is, starting at 1. Increments on retry. */
170
+ attempt: number; /** Epoch ms when this item was registered. */
171
+ createdAt: number; /** Phase history up to this call. Errors have cause stripped. */
172
+ steps: readonly UploadStep[]; /** Caller-supplied metadata from the addFiles command. Never persisted. */
173
+ meta: Record<string, unknown>; /** Safe error from the most recent failed step, if any. */
174
+ lastError?: StepError | undefined; /** Browser File object. Present in most phases; absent when file is not loaded. */
175
+ file?: File | undefined; /** Upload intent from the backend. Present after createIntent succeeds. */
176
+ intent?: Intent.Any<M> | undefined; /** Cancellation signal. */
177
+ signal?: AbortSignal | undefined;
178
+ };
179
+ /** Context for API calls where intent is not yet created but file is loaded (e.g. createIntent) */
180
+ type CreateIntentContext<P extends string, M extends Intent.Map> = Context<P, M> & Required<Pick<Context<P, M>, 'file' | 'signal'>>;
181
+ /** Context for API calls verifying file checksum (e.g. findByChecksum) */
182
+ type FindByChecksumContext<P extends string, M extends Intent.Map> = Context<P, M> & Required<Pick<Context<P, M>, 'file'>>;
183
+ /** Context for API calls executing during/after upload where intent is active (e.g. complete, signPart, completeMultipart) */
184
+ type CompleteContext<P extends string, M extends Intent.Map> = Context<P, M> & Required<Pick<Context<P, M>, 'file' | 'intent' | 'signal'>>;
185
+ /** Context for API abort calls where intent is active but file/signal might be absent (e.g. abort) */
186
+ type AbortContext<P extends string, M extends Intent.Map> = Context<P, M> & Required<Pick<Context<P, M>, 'intent'>>;
187
+ /** Contract definition for your backend API endpoints. */
188
+ type Me<M extends Intent.Map, P extends string, R extends Result.Base = Result.Base> = {
189
+ /** Requests an upload intent from the server. */createIntent(args: {
190
+ purpose: P;
191
+ contentType: string;
192
+ size: number;
193
+ filename: string;
194
+ checksum?: string;
195
+ attempt: number;
196
+ }, ctx: CreateIntentContext<P, M>, ...extra: any[]): Promise<M[keyof M]>; /** Finalizes the upload on the server after bytes have been transferred. */
197
+ complete(args: {
198
+ fileId: string; /** Sanitized filename. Do not use the raw File.name from the browser. */
199
+ filename: string;
200
+ contentType: string;
201
+ size: number;
202
+ checksum?: string;
203
+ attempt: number;
204
+ }, ctx: CompleteContext<P, M>, ...extra: any[]): Promise<R>; /** Optional endpoint to fetch a signed preview/access URL for completed resources. */
205
+ getSignedPreviewUrl?(args: {
206
+ fileId: string;
207
+ key: string;
208
+ purpose: P;
209
+ }, ctx: Context<P, M>, ...extra: any[]): Promise<string>; /** Optional endpoint to verify if the file has already been uploaded previously. */
210
+ findByChecksum?(args: {
211
+ checksum: string;
212
+ purpose: P;
213
+ }, ctx: FindByChecksumContext<P, M>, ...extra: any[]): Promise<R | null>; /** Multipart-specific backend commands. Required if using the multipart strategy. */
214
+ multipart?: {
215
+ signPart(args: {
216
+ fileId: string;
217
+ uploadId: string;
218
+ partNumber: number;
219
+ checksum?: string;
220
+ attempt: number;
221
+ }, ctx: CompleteContext<P, M>, ...extra: any[]): Promise<{
222
+ url: string;
223
+ headers?: Record<string, string>;
224
+ }>;
225
+ completeMultipart(args: {
226
+ fileId: string;
227
+ uploadId: string;
228
+ parts: Array<{
229
+ partNumber: number;
230
+ etag: string;
231
+ }>;
232
+ }, ctx: CompleteContext<P, M>, ...extra: any[]): Promise<unknown>;
233
+ listParts?(args: {
234
+ fileId: string;
235
+ uploadId: string;
236
+ }, ctx: CompleteContext<P, M>, ...extra: any[]): Promise<Array<{
237
+ partNumber: number;
238
+ etag?: string;
239
+ size?: number;
240
+ }>>;
241
+ abort?(args: {
242
+ fileId: string;
243
+ uploadId: string;
244
+ }, ctx: AbortContext<P, M>, ...extra: any[]): Promise<void>;
245
+ }; /** TUS resumable protocol operations. */
246
+ tus?: {
247
+ create(args: {
248
+ fileId: string;
249
+ size: number;
250
+ filename: string;
251
+ contentType: string;
252
+ attempt: number;
253
+ }, ctx: CompleteContext<P, M>, ...extra: any[]): Promise<{
254
+ uploadUrl: string;
255
+ }>;
256
+ getOffset(args: {
257
+ uploadUrl: string;
258
+ }, ctx: CompleteContext<P, M>, ...extra: any[]): Promise<{
259
+ offset: number;
260
+ }>;
261
+ };
262
+ };
263
+ }
264
+ namespace Strategy {
265
+ /** Per-call context handed to a strategy's `start()` method. */
266
+ type Ctx<M extends Intent.Map, C extends Cursor.Map<M>, P extends string, R extends Result.Base, K extends keyof M & string> = {
267
+ localId: string;
268
+ purpose: P;
269
+ file: File;
270
+ fingerprint: FingerprintFile;
271
+ intent: M[K];
272
+ signal: AbortSignal;
273
+ attempt: number;
274
+ createdAt: number;
275
+ steps: readonly UploadStep[];
276
+ lastError?: StepError | undefined;
277
+ meta: Record<string, unknown>;
278
+ transport: {
279
+ put(args: {
280
+ url: string;
281
+ body: Blob;
282
+ headers?: Record<string, string>;
283
+ signal: AbortSignal;
284
+ onProgress?: (u: number, t: number) => void;
285
+ }): Promise<{
286
+ etag?: string | undefined;
287
+ headers?: Record<string, string>;
288
+ }>;
289
+ postForm(args: {
290
+ url: string;
291
+ fields: Record<string, string>;
292
+ file: File | Blob;
293
+ filename?: string;
294
+ signal: AbortSignal;
295
+ onProgress?: (uploadedBytes: number, totalBytes: number) => void;
296
+ }): Promise<{
297
+ etag?: string;
298
+ headers?: Record<string, string>;
299
+ }>;
300
+ patch(args: {
301
+ url: string;
302
+ body: Blob | ArrayBuffer;
303
+ headers?: Record<string, string>;
304
+ signal: AbortSignal;
305
+ onProgress?: (u: number, t: number) => void;
306
+ }): Promise<{
307
+ headers?: Record<string, string>;
308
+ }>;
309
+ get?(args: {
310
+ url: string;
311
+ headers?: Record<string, string>;
312
+ signal: AbortSignal;
313
+ onProgress?: (loaded: number, total: number) => void;
314
+ }): Promise<{
315
+ blob: Blob;
316
+ status: number;
317
+ headers?: Record<string, string>;
318
+ }>;
319
+ head?(args: {
320
+ url: string;
321
+ headers?: Record<string, string>;
322
+ signal: AbortSignal;
323
+ }): Promise<{
324
+ status: number;
325
+ headers: Record<string, string>;
326
+ }>;
327
+ };
328
+ api: Api.Me<M, P, R>;
329
+ reportProgress: (p: {
330
+ uploadedBytes: number;
331
+ totalBytes: number;
332
+ }) => void;
333
+ readCursor: () => C[K] | undefined;
334
+ persistCursor: (cursor: C[K] | undefined) => void;
335
+ };
336
+ /** A single upload strategy implementation. */
337
+ type Me<M extends Intent.Map, C extends Cursor.Map<M>, P extends string, R extends Result.Base, K extends keyof M & string> = {
338
+ id: K;
339
+ resumable: boolean;
340
+ start(ctx: Ctx<M, C, P, R, K>): Promise<void>;
341
+ };
342
+ /** Registry of available upload strategies, keyed by strategy id. */
343
+ type Registry<M extends Intent.Map, C extends Cursor.Map<M>, P extends string = string, R extends Result.Base = Result.Base> = {
344
+ get<K extends keyof M & string>(id: K): Me<M, C, P, R, K> | undefined;
345
+ has(id: string): id is keyof M & string;
346
+ set<K extends keyof M & string>(strategy: Me<M, C, P, R, K>): void;
347
+ };
348
+ }
349
+ }
350
+ //#endregion
351
+ //#region src/core/contracts/transport/transport.types.d.ts
352
+ /**
353
+ * Transport contracts: the network layer the engine uses to move bytes.
354
+ * @author wildduck2 <https://github.com/wildduck2>
355
+ */
356
+ declare namespace Transport {
357
+ /**
358
+ * Abstraction layer for network operations.
359
+ * Allows switching between XHR (browser) or other implementations (testing/Node).
360
+ *
361
+ * Designed to support:
362
+ * - Deterministic progress tracking (requires XHR in browsers)
363
+ * - Cancellation via AbortSignal
364
+ * - Header parsing (ETag extraction)
365
+ */
366
+ type Options = {
367
+ /**
368
+ * Performs an HTTP PUT request (typically for S3 signed URLs).
369
+ */
370
+ put(args: {
371
+ url: string;
372
+ body: Blob;
373
+ headers?: Record<string, string>;
374
+ signal: AbortSignal;
375
+ onProgress?: (u: number, t: number) => void;
376
+ }): Promise<{
377
+ etag?: string | undefined;
378
+ headers?: Record<string, string>;
379
+ }>;
380
+ /**
381
+ * Performs an HTTP POST multipart request.
382
+ */
383
+ postForm(args: {
384
+ url: string;
385
+ fields: Record<string, string>;
386
+ file: File | Blob;
387
+ filename?: string;
388
+ signal: AbortSignal;
389
+ onProgress?: (uploadedBytes: number, totalBytes: number) => void;
390
+ }): Promise<{
391
+ etag?: string;
392
+ headers?: Record<string, string>;
393
+ }>;
394
+ /**
395
+ * Performs an HTTP request.
396
+ */
397
+ patch(args: {
398
+ url: string;
399
+ body: Blob | ArrayBuffer;
400
+ headers?: Record<string, string>;
401
+ signal: AbortSignal;
402
+ onProgress?: (u: number, t: number) => void;
403
+ }): Promise<{
404
+ headers?: Record<string, string>;
405
+ }>;
406
+ /**
407
+ * Optional HTTP GET download. Streams the response so `onProgress` can
408
+ * report bytes as they arrive. Not every transport implements it — check
409
+ * for presence before calling.
410
+ */
411
+ get?(args: {
412
+ url: string;
413
+ headers?: Record<string, string>;
414
+ signal: AbortSignal;
415
+ onProgress?: (loaded: number, total: number) => void;
416
+ }): Promise<{
417
+ blob: Blob;
418
+ status: number;
419
+ headers?: Record<string, string>;
420
+ }>;
421
+ /**
422
+ * Optional HTTP HEAD. Used by resumable strategies (tus) to read the
423
+ * server's current `Upload-Offset` before resuming. Not every transport
424
+ * implements it — check for presence before calling.
425
+ */
426
+ head?(args: {
427
+ url: string;
428
+ headers?: Record<string, string>;
429
+ signal: AbortSignal;
430
+ }): Promise<{
431
+ status: number;
432
+ headers: Record<string, string>;
433
+ }>;
434
+ };
435
+ type XhrArgs = {
436
+ url: string;
437
+ signal?: AbortSignal;
438
+ headers?: Record<string, string>;
439
+ onProgress?: (loaded: number, total: number) => void;
440
+ };
441
+ }
442
+ //#endregion
443
+ //#region src/core/contracts/transport/transport.d.ts
444
+ /**
445
+ * Browser-native XHR transport. Uses `XMLHttpRequest` over `fetch` because
446
+ * `fetch` lacks cross-browser upload-progress events.
447
+ * @author wildduck2 <https://github.com/wildduck2>
448
+ */
449
+ declare function createXHRTransport(): Transport.Options & {
450
+ /** Optional PATCH for tus-style strategies. */patch?: (args: Transport.XhrArgs & {
451
+ body: Blob | ArrayBuffer;
452
+ }) => Promise<{
453
+ headers: Record<string, string>;
454
+ }>;
455
+ };
456
+ //#endregion
457
+ //#region src/core/contracts/transport/transport.fetch.d.ts
458
+ /**
459
+ * Create a `fetch`-backed {@link Transport.Options} implementation.
460
+ * @author wildduck2 <https://github.com/wildduck2>
461
+ */
462
+ declare function createFetchTransport(): Transport.Options;
463
+ //#endregion
464
+ //#region src/core/errors.d.ts
465
+ /**
466
+ * Structured extra context properties for upload errors.
467
+ * @author wildduck2 <https://github.com/wildduck2>
468
+ */
469
+ type UploadErrorContext = Record<string, unknown>;
470
+ /**
471
+ * Base typed error thrown by the upload engine.
472
+ *
473
+ * Always carries a stable error classification `code` and an immutable, static
474
+ * `message`. Attic strings (like raw input details) live under `context` or subclass-specific fields.
475
+ * @author wildduck2 <https://github.com/wildduck2>
476
+ */
477
+ declare class UploadEngineError extends Error {
478
+ /** Stable machine-readable error code. */
479
+ readonly code: string;
480
+ /** Structured context details. */
481
+ readonly context?: UploadErrorContext;
482
+ /** Original error, if any, mapped per ES2022. */
483
+ readonly cause?: unknown;
484
+ /** Flag specifying whether the error recovery system should schedule retries. */
485
+ readonly retryable: boolean;
486
+ constructor(code: string, init?: {
487
+ message?: string | undefined;
488
+ context?: UploadErrorContext | undefined;
489
+ cause?: unknown;
490
+ retryable?: boolean | undefined;
491
+ });
492
+ }
493
+ /**
494
+ * Error thrown when file validation rules fail.
495
+ * @author wildduck2 <https://github.com/wildduck2>
496
+ */
497
+ declare class UploadValidationError extends UploadEngineError {
498
+ /** Structured rejection reason details. */
499
+ readonly reason: Contracts.Validation.Rejection;
500
+ constructor(reason: Contracts.Validation.Rejection, message?: string, init?: {
501
+ cause?: unknown;
502
+ context?: UploadErrorContext;
503
+ });
504
+ }
505
+ /**
506
+ * Error thrown when an upload strategy identifier is not registered.
507
+ * @author wildduck2 <https://github.com/wildduck2>
508
+ */
509
+ declare class UploadStrategyMissingError extends UploadEngineError {
510
+ /** Unregistered strategy identifier. */
511
+ readonly strategy: string;
512
+ constructor(strategy: string, message?: string, init?: {
513
+ cause?: unknown;
514
+ context?: UploadErrorContext;
515
+ });
516
+ }
517
+ /**
518
+ * Error thrown when an upload is aborted (paused or canceled).
519
+ * @author wildduck2 <https://github.com/wildduck2>
520
+ */
521
+ declare class UploadAbortError extends UploadEngineError {
522
+ /** Reason context for the abort. */
523
+ readonly reason: 'pause' | 'cancel' | 'unknown';
524
+ constructor(reason: 'pause' | 'cancel' | 'unknown', message?: string, init?: {
525
+ cause?: unknown;
526
+ context?: UploadErrorContext;
527
+ });
528
+ }
529
+ /**
530
+ * Error thrown on transport-level connection or fetch failures.
531
+ * @author wildduck2 <https://github.com/wildduck2>
532
+ */
533
+ declare class UploadNetworkError extends UploadEngineError {
534
+ constructor(message?: string, init?: {
535
+ cause?: unknown;
536
+ context?: UploadErrorContext;
537
+ });
538
+ }
539
+ /**
540
+ * Error thrown when a non-2xx HTTP status response is returned.
541
+ * @author wildduck2 <https://github.com/wildduck2>
542
+ */
543
+ declare class UploadHttpError extends UploadEngineError {
544
+ /** HTTP response status code. */
545
+ readonly status: number;
546
+ /** HTTP response status text message. */
547
+ readonly statusText?: string;
548
+ constructor(status: number, message?: string, init?: {
549
+ statusText?: string | undefined;
550
+ cause?: unknown;
551
+ context?: UploadErrorContext | undefined;
552
+ retryable?: boolean | undefined;
553
+ });
554
+ }
555
+ /**
556
+ * Error thrown when a timeout occurs during network operations.
557
+ * @author wildduck2 <https://github.com/wildduck2>
558
+ */
559
+ declare class UploadTimeoutError extends UploadEngineError {
560
+ constructor(message?: string, init?: {
561
+ cause?: unknown;
562
+ context?: UploadErrorContext;
563
+ });
564
+ }
565
+ /**
566
+ * Error thrown on authentication / authorization failures.
567
+ * @author wildduck2 <https://github.com/wildduck2>
568
+ */
569
+ declare class UploadAuthError extends UploadEngineError {
570
+ constructor(message?: string, init?: {
571
+ cause?: unknown;
572
+ context?: UploadErrorContext;
573
+ });
574
+ }
575
+ /**
576
+ * Error thrown when the endpoint indicates rate limits are exceeded.
577
+ * @author wildduck2 <https://github.com/wildduck2>
578
+ */
579
+ declare class UploadRateLimitError extends UploadEngineError {
580
+ /** Optional delay value recommended by the server before retry. */
581
+ readonly retryAfterMs?: number;
582
+ constructor(message?: string, init?: {
583
+ retryAfterMs?: number;
584
+ cause?: unknown;
585
+ context?: UploadErrorContext;
586
+ });
587
+ }
588
+ /**
589
+ * Error thrown when custom backend/server validation errors are reported.
590
+ * @author wildduck2 <https://github.com/wildduck2>
591
+ */
592
+ declare class UploadServerError extends UploadEngineError {
593
+ /** Server-defined diagnostic code. */
594
+ readonly serverCode?: string;
595
+ constructor(message?: string, init?: {
596
+ serverCode?: string;
597
+ cause?: unknown;
598
+ context?: UploadErrorContext;
599
+ });
600
+ }
601
+ /**
602
+ * Fallback error class for unclassified or legacy throws.
603
+ * @author wildduck2 <https://github.com/wildduck2>
604
+ */
605
+ declare class UploadUnknownError extends UploadEngineError {
606
+ constructor(message?: string, init?: {
607
+ cause?: unknown;
608
+ context?: UploadErrorContext;
609
+ });
610
+ }
611
+ /**
612
+ * Runtime error stored on items and passed through engine events.
613
+ * Plain contract shapes and {@link UploadEngineError} subclasses are both valid.
614
+ * @author wildduck2 <https://github.com/wildduck2>
615
+ */
616
+ type UploadError = Contracts.Errors.Error | UploadEngineError;
617
+ //#endregion
618
+ //#region src/core/persistence/persistence.types.d.ts
619
+ /**
620
+ * Persistence layer interfaces and options.
621
+ * @author wildduck2 <https://github.com/wildduck2>
622
+ */
623
+ declare namespace UploadPersistence {
624
+ /**
625
+ * Type context handed to deserializers to validate dynamic properties during recovery.
626
+ *
627
+ * @template M - Intent map type
628
+ * @template P - Purpose string union type
629
+ */
630
+ type DeserializeContext<M extends Contracts.Intent.Map, P extends string> = {
631
+ /** Guard checking if a purpose string is valid. */isPurpose?: ((value: string) => value is P) | undefined; /** Guard checking if an intent matches expected schemas. */
632
+ isIntent?: ((value: unknown) => value is M[keyof M]) | undefined; /** Query to verify if a strategy discriminant is active in runtime strategies. */
633
+ hasStrategy?: ((value: string) => boolean) | undefined;
634
+ };
635
+ /**
636
+ * Configuration options for the upload store persistence manager.
637
+ *
638
+ * @template M - Intent map type
639
+ * @template C - Cursor map type
640
+ * @template P - Purpose string union type
641
+ * @template R - Backend result shape
642
+ */
643
+ type Options<M extends Contracts.Intent.Map, C extends Contracts.Cursor.Map<M>, P extends string, R extends Contracts.Result.Base> = {
644
+ /** Target key used to store the serialized string representation of snapshots. */key: string; /** Schema version identifier. Increment when changing models to run safe migrations. */
645
+ version: number; /** Milliseconds to wait before writing changes to disk (throttling storage writes). */
646
+ debounceMs?: number; /** Target storage adapter (e.g. LocalStorageAdapter, IndexedDBAdapter). */
647
+ adapter: Adapter;
648
+ /**
649
+ * Optional custom serialization mapper.
650
+ */
651
+ serialize?: (state: Engine.State<M, C, P, R>, version: number) => Snapshot<M, C, P>;
652
+ /**
653
+ * Optional custom deserialization mapper.
654
+ */
655
+ deserialize?: (raw: unknown, ctx: DeserializeContext<M, P>) => Engine.State<M, C, P, R> | null;
656
+ /**
657
+ * Runtime validation guard for purpose strings. Required if using the default deserializer.
658
+ */
659
+ isPurpose?: ((value: string) => value is P) | undefined;
660
+ /**
661
+ * Runtime validation guard for intent objects. Required if using the default deserializer.
662
+ */
663
+ isIntent?: ((value: unknown) => value is M[keyof M]) | undefined;
664
+ };
665
+ /**
666
+ * Plain-object representation of a stored upload item.
667
+ * Files cannot be fully serialized; hence their binary metadata is stashed.
668
+ */
669
+ type PersistedItem<M extends Contracts.Intent.Map, C extends Contracts.Cursor.Map<M>, P extends string> = {
670
+ /** Unique client-side file identifier. */id: string; /** Upload purpose. */
671
+ purpose: P; /** Target status phase key (e.g. `'uploading'`, `'paused'`). */
672
+ status: string; /** Serialized metadata of the file. */
673
+ file: {
674
+ /** Base name. */name: string; /** Size in bytes. */
675
+ size: number; /** Claimed MIME type. */
676
+ type: string; /** Mod date timestamp in ms. */
677
+ lastModified: number; /** Checksum fingerprint hash if calculated. */
678
+ checksum?: string | undefined;
679
+ }; /** The active backend intent payload. */
680
+ intent: Contracts.Intent.Any<M>; /** Strategy-defined resume cursor state. */
681
+ cursor?: Contracts.Cursor.Any<C> | undefined; /** Current progress measurements. */
682
+ progress?: {
683
+ uploadedBytes: number;
684
+ totalBytes: number;
685
+ pct?: number | undefined;
686
+ } | undefined;
687
+ };
688
+ /**
689
+ * A minimal, serializable representation of an upload item that is safe to store
690
+ * in persistence (LocalStorage, IndexedDB, etc).
691
+ *
692
+ * @typeParam M - Map of upload intent variants keyed by intent kind (e.g. `direct`, `multipart`).
693
+ * @typeParam C - Map of cursor shapes keyed by {@link M}'s intent kinds.
694
+ * @typeParam P - Union of allowed `purpose` strings for your app (e.g. `"avatar" | "document"`).
695
+ */
696
+ type Snapshot<M extends Contracts.Intent.Map, C extends Contracts.Cursor.Map<M>, P extends string> = {
697
+ /** Persistence schema version (not app version). */version: number; /** Unix epoch milliseconds when this snapshot was written. */
698
+ createdAt: number; /** List of persisted upload items. */
699
+ items: Record<string, PersistedItem<M, C, P>>;
700
+ };
701
+ /**
702
+ * Driver interface for persisting upload store snapshots.
703
+ */
704
+ type Adapter = {
705
+ /**
706
+ * Resolves and returns the stored snapshot payload.
707
+ * Can return null if no snapshot exists.
708
+ */
709
+ load(key: string): unknown | null | Promise<unknown | null>;
710
+ /**
711
+ * Saves a snapshot payload to the target storage location.
712
+ */
713
+ save(key: string, snapshot: unknown): void | Promise<void>;
714
+ /**
715
+ * Deletes the snapshot record.
716
+ */
717
+ clear(key: string): void | Promise<void>;
718
+ };
719
+ }
720
+ //#endregion
721
+ //#region src/core/persistence/adapters.indexeddb.d.ts
722
+ /**
723
+ * Persistence adapter backed by IndexedDB, for durable snapshot storage in the
724
+ * browser without the size limits of `localStorage`.
725
+ * @author wildduck2 <https://github.com/wildduck2>
726
+ */
727
+ declare const IndexedDBAdapter: UploadPersistence.Adapter;
728
+ //#endregion
729
+ //#region src/core/persistence/adapters.local.d.ts
730
+ /**
731
+ * Persistence adapter backed by `localStorage`. Synchronous and simple; best
732
+ * suited to small snapshots.
733
+ * @author wildduck2 <https://github.com/wildduck2>
734
+ */
735
+ declare const LocalStorageAdapter: UploadPersistence.Adapter;
736
+ //#endregion
737
+ //#region src/core/persistence/adapters.memory.d.ts
738
+ /**
739
+ * Create an in-memory {@link PersistenceAdapter} backed by a fresh `Map`.
740
+ *
741
+ * Each call returns an isolated store. Multi-engine and multi-tenant
742
+ * deployments must use the factory so engine instances cannot read or
743
+ * overwrite each other's snapshots.
744
+ *
745
+ * @example
746
+ * ```ts
747
+ * const adapter = createMemoryAdapter()
748
+ * createUploadStore({ persistence: { adapter, key: 'tenant-a' } })
749
+ * ```
750
+ * @author wildduck2 <https://github.com/wildduck2>
751
+ */
752
+ declare function createMemoryAdapter(): UploadPersistence.Adapter;
753
+ /**
754
+ * Shared in-memory adapter instance. Convenient for single-engine apps; use
755
+ * {@link createMemoryAdapter} when isolation between engines is required.
756
+ * @author wildduck2 <https://github.com/wildduck2>
757
+ */
758
+ declare const MemoryAdapter: UploadPersistence.Adapter;
759
+ //#endregion
760
+ //#region src/core/persistence/persistence.d.ts
761
+ /**
762
+ * Serializes the current upload state into a JSON-safe structure.
763
+ * Only serializes items that have a valid 'intent', as these are the only ones
764
+ * that can be resumed cleanly.
765
+ * @author wildduck2 <https://github.com/wildduck2>
766
+ */
767
+ declare function serializeSnapshot<M extends Contracts.Intent.Map, C extends Contracts.Cursor.Map<M>, P extends string, R extends Contracts.Result.Base>(state: Engine.State<M, C, P, R>, version: number): UploadPersistence.Snapshot<M, C, P>;
768
+ /**
769
+ * Deserializes a persisted snapshot back into a store state.
770
+ *
771
+ * Important:
772
+ * - Browser `File` objects cannot be restored from persistence.
773
+ * - We restore resumable items (those with a cursor) into the `paused` phase,
774
+ * with `file` left undefined. Your UI can ask the user to rebind the file.
775
+ * @author wildduck2 <https://github.com/wildduck2>
776
+ */
777
+ declare function deserializeSnapshot<M extends Contracts.Intent.Map, C extends Contracts.Cursor.Map<M>, P extends string, R extends Contracts.Result.Base>(raw: unknown, opts: UploadPersistence.DeserializeContext<M, P>): Engine.State<M, C, P, R> | null;
778
+ //#endregion
779
+ //#region src/core/utils/emitter/emitter.types.d.ts
780
+ declare namespace Emitter {
781
+ /**
782
+ * Minimal typed event emitter interface.
783
+ *
784
+ * Use this to expose strongly-typed events from your store.
785
+ *
786
+ * @typeParam E - Event map (`eventName -> payload`).
787
+ */
788
+ type TypedEmitter<E extends Record<string, unknown>> = {
789
+ /**
790
+ * Subscribe to an event.
791
+ * @returns Unsubscribe function.
792
+ */
793
+ on<K extends keyof E & string>(type: K, cb: (payload: E[K]) => void): () => void;
794
+ /**
795
+ * Unsubscribe from an event.
796
+ */
797
+ off<K extends keyof E & string>(type: K, cb: (payload: E[K]) => void): void; /** Emit an event to all listeners. */
798
+ emit<K extends keyof E & string>(type: K, payload: E[K]): void;
799
+ };
800
+ /**
801
+ * Callback invoked when a listener throws during `emit`, so one bad listener
802
+ * cannot break the dispatch loop. Receives the event type, the thrown error,
803
+ * and the listener that threw.
804
+ */
805
+ type ErrorHandler = (type: string, error: unknown, cb: (...args: any[]) => void) => void;
806
+ /**
807
+ * Listener registry, bucketed by event type.
808
+ *
809
+ * @template E Event map.
810
+ */
811
+ type ListenerMap<E extends Record<string, unknown>> = Partial<{ [K in keyof E & string]: Set<(payload: E[K]) => void> }>;
812
+ }
813
+ //#endregion
814
+ //#region src/core/engine/reducer.d.ts
815
+ declare function createReducer<M extends Contracts.Intent.Map, C extends Contracts.Cursor.Map<M>, P extends string, R extends Contracts.Result.Base = Contracts.Result.Base>(): (state: Engine.State<M, C, P, R>, event: Engine.Command<P> | Engine.Event<M, C, P, R>) => Engine.State<M, C, P, R>;
816
+ //#endregion
817
+ //#region src/core/engine/store/store.types.d.ts
818
+ /**
819
+ * Store-level namespaces and contracts.
820
+ * @author wildduck2 <https://github.com/wildduck2>
821
+ */
822
+ declare namespace Store {
823
+ /**
824
+ * Public upload store interface used by UI adapters and application code.
825
+ *
826
+ * Coordinates commands, subscriptions, event bindings, and lifecycle states.
827
+ *
828
+ * @template M - Intent map type (keyed by strategy id)
829
+ * @template C - Cursor map type (keyed by strategy id)
830
+ * @template P - Purpose string union type
831
+ * @template R - Backend result shape
832
+ */
833
+ type UploadStore<M extends Contracts.Intent.Map, C extends Contracts.Cursor.Map<M>, P extends string, R extends Contracts.Result.Base = Contracts.Result.Base> = {
834
+ /**
835
+ * Returns the current immutable state snapshot.
836
+ * Use this in custom React lifecycle bindings or debug inspectors.
837
+ */
838
+ getSnapshot(): Engine.State<M, C, P, R>;
839
+ /**
840
+ * Subscribes to any internal state change.
841
+ * Triggered after reducers process events and side effects are queued.
842
+ *
843
+ * @param listener - Callback invoked on state updates.
844
+ * @returns An unsubscribe function.
845
+ */
846
+ subscribe(listener: () => void): () => void;
847
+ /**
848
+ * Dispatches a command to initiate state transitions (e.g. adding files, pausing, canceling).
849
+ *
850
+ * @param cmd - Public command payload.
851
+ */
852
+ dispatch(cmd: Engine.Command<P>): void;
853
+ /**
854
+ * Binds a listener to a specific typed event (e.g. `'upload.progress'`).
855
+ *
856
+ * @param type - Event name key.
857
+ * @param cb - Event listener callback.
858
+ * @returns An unsubscribe function.
859
+ */
860
+ on: <K extends keyof Engine.EventMap<M, C, P, R> & string>(type: K, cb: (payload: Engine.EventMap<M, C, P, R>[K]) => void) => () => void;
861
+ /**
862
+ * Removes an event listener.
863
+ *
864
+ * @param type - Event name key.
865
+ * @param cb - Event listener callback.
866
+ */
867
+ off: <K extends keyof Engine.EventMap<M, C, P, R> & string>(type: K, cb: (payload: Engine.EventMap<M, C, P, R>[K]) => void) => void;
868
+ /**
869
+ * Resolves when the specified items reach a terminal state
870
+ * (completed, failed, canceled, or missing).
871
+ *
872
+ * @param localIds - Array of registered client file IDs.
873
+ */
874
+ waitFor(localIds: string[]): Promise<Array<Engine.Outcome<R>>>;
875
+ };
876
+ /**
877
+ * Configuration options for constructing an upload store.
878
+ *
879
+ * @template M - Intent map type (keyed by strategy id)
880
+ * @template C - Cursor map type (keyed by strategy id)
881
+ * @template P - Purpose string union type
882
+ * @template R - Backend result shape
883
+ */
884
+ type Options<M extends Contracts.Intent.Map, C extends Contracts.Cursor.Map<M>, P extends string, R extends Contracts.Result.Base = Contracts.Result.Base> = {
885
+ /** Initial state to hydrate from (e.g. recovered from a persistence snapshot). */initialState?: Engine.State<M, C, P, R>; /** Engine configuration (defaults applied for unspecified settings). */
886
+ config?: Partial<Engine.Config<P>>; /** Persistence adapter configuration (key prefix, adapters, storage handlers). */
887
+ persistence?: UploadPersistence.Options<M, C, P, R>; /** Your backend API implementation. */
888
+ api: Contracts.Api.Me<M, P, R>; /** Transport layer options for HTTP byte transfers. */
889
+ transport?: Transport.Options; /** Registry of available upload strategies (multipart, POST forms, simple PUTs, TUS). */
890
+ strategies: Contracts.Strategy.Registry<M, C, P, R>; /** Plugin modules to extend behavior (metrics, logging, analytics). */
891
+ plugins?: Array<Engine.Plugin<M, C, P, R>>; /** Lifecycle hooks for observing internal events. */
892
+ hooks?: Engine.Hooks<M, C, P, R>;
893
+ /**
894
+ * Override to use a custom fingerprinting implementation (e.g. a custom hash).
895
+ */
896
+ fingerprint?: (file: File) => Contracts.FingerprintFile;
897
+ /**
898
+ * Custom per-file validator called after built-in config constraints pass.
899
+ * Return a rejection to block the file; return null to allow it.
900
+ */
901
+ validateFile?: (file: File, purpose: P) => Contracts.Validation.Rejection | null;
902
+ /**
903
+ * Custom error normalizer.
904
+ * Converts raw thrown values into a standardized Contracts.Errors.Error.
905
+ */
906
+ errorNormalizer?: (err: unknown) => Contracts.Errors.Error;
907
+ };
908
+ /**
909
+ * Tracks an in-flight upload operation.
910
+ */
911
+ type InflightUpload = {
912
+ /** AbortController for this upload. */controller: AbortController; /** Whether the upload is running normally, being paused, or being canceled. */
913
+ mode: 'normal' | 'pause' | 'cancel'; /** True once the strategy's start() has been called. */
914
+ started: boolean;
915
+ };
916
+ /**
917
+ * Internal execution context shared across store utilities, handlers, and schedulers.
918
+ */
919
+ type Runtime<M extends Contracts.Intent.Map, C extends Contracts.Cursor.Map<M>, P extends string, R extends Contracts.Result.Base = Contracts.Result.Base> = {
920
+ /** Resolved store options with all defaults applied. */opts: Options<M, C, P, R> & {
921
+ config: Engine.Config<P>;
922
+ transport: Transport.Options;
923
+ }; /** Current engine state. */
924
+ state: Engine.State<M, C, P, R>; /** Active state change subscribers. */
925
+ listeners: Set<() => void>; /** Typed event emitter. */
926
+ emitter: Emitter.TypedEmitter<Engine.EventMap<M, C, P, R>>; /** Reducer function. */
927
+ reduce: ReturnType<typeof createReducer<M, C, P, R>>; /** Inflight upload operations keyed by localId. */
928
+ inflightUploads: Map<string, InflightUpload>; /** Inflight intent creation requests keyed by localId. */
929
+ inflightIntents: Map<string, AbortController>; /** Inflight complete() calls keyed by localId. */
930
+ inflightCompletes: Map<string, AbortController>; /** Queued async side effects. */
931
+ effectQueue: Array<() => Promise<void>>; /** True while the effect queue is being drained. */
932
+ processingEffects: boolean; /** True while scheduleWork is running, preventing re-entrant calls. */
933
+ scheduling: boolean; /** Notifies all state change subscribers. */
934
+ notify: () => void; /** Starts queued uploads when concurrency slots are available. */
935
+ scheduleWork: () => void; /** Applies an internal event through the reducer and notifies subscribers. */
936
+ applyInternal: (event: Engine.Event<M, C, P, R>) => void; /** Runs a command through the reducer. */
937
+ applyCommand: (cmd: Engine.Command<P>) => void; /** Adds an async side effect to the execution queue. */
938
+ enqueueEffect: (effect: () => Promise<void>) => void; /** Drains the effect queue, running each side effect in order. */
939
+ processEffects: () => Promise<void>; /** Dispatches a public command. */
940
+ dispatch: (cmd: Engine.Command<P>) => void;
941
+ };
942
+ }
943
+ //#endregion
944
+ //#region src/core/engine/store/index.d.ts
945
+ /**
946
+ * Creates an upload store instance.
947
+ *
948
+ * This is the main runtime object you interact with from the outside:
949
+ * - dispatch user commands (add files, start, pause, cancel, resume)
950
+ * - subscribe to state changes (for UI rendering)
951
+ * - subscribe to typed events (for progress, errors, and lifecycle)
952
+ *
953
+ * Plugins are initialized once during construction and receive a minimal store
954
+ * proxy (events, dispatch, snapshot access) to avoid tight coupling.
955
+ *
956
+ * @template M - Intent map type (keyed by strategy id)
957
+ * @template C - Cursor map type (keyed by strategy id)
958
+ * @template P - Purpose string union type
959
+ *
960
+ * @param opts - Store options (config, backend API, strategies, transport, hooks)
961
+ * @returns A configured {@link Store.UploadStore} instance.
962
+ * @author wildduck2 <https://github.com/wildduck2>
963
+ */
964
+ declare function createUploadStore<M extends Contracts.Intent.Map, C extends Contracts.Cursor.Map<M>, P extends string, R extends Contracts.Result.Base = Contracts.Result.Base>(opts: Store.Options<M, C, P, R>): Store.UploadStore<M, C, P, R>;
965
+ //#endregion
966
+ //#region src/core/engine/engine.types.d.ts
967
+ /**
968
+ * Engine-level type surface containing runtime state models, commands, progress,
969
+ * and configuration options.
970
+ * @author wildduck2 <https://github.com/wildduck2>
971
+ */
972
+ declare namespace Engine {
973
+ /**
974
+ * Return value from a retry policy determining if and when a task should be re-scheduled.
975
+ */
976
+ export type RetryDecision = {
977
+ /** The task has failed terminal or cannot recover. */retryable: false;
978
+ } | {
979
+ /** The task is recoverable and should retry. */retryable: true; /** Delay duration in milliseconds before invoking the next attempt. */
980
+ delayMs: number;
981
+ };
982
+ /**
983
+ * Global upload engine configuration.
984
+ *
985
+ * Coordinates concurrency limits, retry strategies, constraints, and validation.
986
+ *
987
+ * @typeParam P - Union of allowed `purpose` strings for your app (e.g. `"avatar" | "attachment"`).
988
+ */
989
+ export type Config<P extends string> = {
990
+ /**
991
+ * Maximum number of parallel uploads active at any time.
992
+ * Queued items wait until active uploads complete or fail.
993
+ */
994
+ maxConcurrentUploads: number;
995
+ /**
996
+ * Auto-start uploads for specific purposes.
997
+ * - Array form: only files with these purposes automatically begin uploading on registration.
998
+ * - Function form: dynamic callback determining whether to auto-start.
999
+ */
1000
+ autoStart?: (readonly P[] | ((purpose: P) => boolean)) | undefined;
1001
+ /**
1002
+ * Throttle delay in milliseconds for progress events.
1003
+ * Limits rendering updates and state changes under busy progress flows.
1004
+ */
1005
+ progressThrottleMs: number;
1006
+ /**
1007
+ * Validation rules keyed by purpose.
1008
+ */
1009
+ validation: Partial<Record<P, Contracts.ValidationRules>>;
1010
+ /**
1011
+ * Maximum number of retry attempts permitted for upload/intent actions.
1012
+ */
1013
+ maxAttempts: number;
1014
+ /**
1015
+ * Custom retry policy handler.
1016
+ * Overrides default exponential backoff calculation.
1017
+ */
1018
+ retryPolicy?: ((ctx: {
1019
+ /** The active execution phase. */phase: 'intent' | 'upload' | 'complete'; /** Current attempt number (starting at 1). */
1020
+ attempt: number; /** The normalized error structure. */
1021
+ error: UploadError;
1022
+ }) => RetryDecision) | undefined;
1023
+ /**
1024
+ * Maximum number of items to keep in memory/state.
1025
+ * When exceeded, oldest completed/canceled items are evicted automatically.
1026
+ *
1027
+ * Set to `undefined` for no limit (not recommended for long-running single-page apps).
1028
+ */
1029
+ maxItems: number;
1030
+ /**
1031
+ * Duration in milliseconds after which completed items are evicted from the store.
1032
+ * Set to `undefined` to preserve completed items indefinitely.
1033
+ */
1034
+ completedItemTTL?: number | undefined;
1035
+ /**
1036
+ * Set to `true` to validate files by sniffing magic bytes/mime signature
1037
+ * and rejecting files whose suffix does not match structural magic numbers.
1038
+ */
1039
+ strictMimeMatch?: boolean | undefined;
1040
+ /**
1041
+ * File-size boundary in bytes between the two checksum paths. At or below
1042
+ * it, files hash inline with native Web Crypto (fastest). Above it, files
1043
+ * hash incrementally in bounded slices — off the main thread via a Web
1044
+ * Worker when available — so large files no longer freeze the UI and are
1045
+ * still deduplicated. Set to `null` or `undefined` for the default (64 MiB).
1046
+ */
1047
+ checksumMaxSize?: number | null | undefined;
1048
+ };
1049
+ /**
1050
+ * Upload progress snapshot.
1051
+ */
1052
+ export type Progress = {
1053
+ /** Bytes uploaded so far. */uploadedBytes: number; /** Total bytes to upload. */
1054
+ totalBytes: number; /** Percent complete (0..100). */
1055
+ pct: number;
1056
+ };
1057
+ /**
1058
+ * Describes how a `completed` upload item resolved.
1059
+ * - `'upload'`: standard byte transfer.
1060
+ * - `'dedupe'`: server matched existing file checksum, skipping byte transfer.
1061
+ */
1062
+ export type CompletionKind = 'upload' | 'dedupe';
1063
+ /**
1064
+ * Terminal outcome returned by `waitFor`.
1065
+ *
1066
+ * @template R Result type carried on successful completion.
1067
+ */
1068
+ export type Outcome<R extends Contracts.Result.Base> = {
1069
+ localId: string;
1070
+ status: 'completed';
1071
+ completedBy: CompletionKind;
1072
+ result: R;
1073
+ } | {
1074
+ localId: string;
1075
+ status: 'error';
1076
+ error: UploadError;
1077
+ } | {
1078
+ localId: string;
1079
+ status: 'canceled';
1080
+ } | {
1081
+ localId: string;
1082
+ status: 'missing';
1083
+ /**
1084
+ * Why the id is missing.
1085
+ * - `'removed'`: explicit user removal.
1086
+ * - `'evicted'`: automatically removed (maxItems/TTL rules).
1087
+ * - `'never-existed'`: id was never registered.
1088
+ * - `'destroyed'`: store was destroyed.
1089
+ */
1090
+ reason: 'removed' | 'evicted' | 'never-existed' | 'destroyed';
1091
+ };
1092
+ /**
1093
+ * Public commands dispatched to the upload store.
1094
+ *
1095
+ * @template P Purpose discriminator string.
1096
+ */
1097
+ export type Command<P extends string> = {
1098
+ /** Register files into the upload store for a specific purpose. */type: 'addFiles';
1099
+ files: File[];
1100
+ purpose: P; /** Optional caller metadata forwarded to every backend API call for this file. */
1101
+ meta?: Record<string, unknown> | undefined;
1102
+ } | {
1103
+ /** Start uploading a specific file. */type: 'start';
1104
+ localId: string;
1105
+ } | {
1106
+ /** Start all queued files, optionally filtering by purpose. */type: 'startAll';
1107
+ purpose?: P;
1108
+ } | {
1109
+ /** Pause an active upload. */type: 'pause';
1110
+ localId: string;
1111
+ } | {
1112
+ /** Pause all active uploads, optionally filtering by purpose. */type: 'pauseAll';
1113
+ purpose?: P;
1114
+ } | {
1115
+ /** Resume a paused upload. */type: 'resume';
1116
+ localId: string;
1117
+ } | {
1118
+ /** Cancel a pending or active upload. */type: 'cancel';
1119
+ localId: string;
1120
+ } | {
1121
+ /** Cancel all pending and active uploads, optionally filtering by purpose. */type: 'cancelAll';
1122
+ purpose?: P;
1123
+ } | {
1124
+ /** Retry a failed upload item. */type: 'retry';
1125
+ localId: string;
1126
+ } | {
1127
+ /** Re-bind a new browser `File` object to a resumed/paused item missing a file reference. */type: 'rebind';
1128
+ localId: string;
1129
+ file: File;
1130
+ } | {
1131
+ /** Remove an item from the store state entirely. */type: 'remove';
1132
+ localId: string;
1133
+ };
1134
+ /**
1135
+ * Const mapping of upload stages.
1136
+ */
1137
+ export const Phases: {
1138
+ /** Initial validation checks are running. */readonly validating: "validating"; /** Fetching signed URLs and strategies from backend. */
1139
+ readonly creating_intent: "creating_intent"; /** Ready to start uploading bytes. */
1140
+ readonly ready: "ready"; /** Waiting in queue (concurrency cap reached). */
1141
+ readonly queued: "queued"; /** Actively transferring bytes. */
1142
+ readonly uploading: "uploading"; /** Upload paused; resumable state preserved. */
1143
+ readonly paused: "paused"; /** Triggering backend finalization. */
1144
+ readonly completing: "completing"; /** File is fully completed and registered on backend. */
1145
+ readonly completed: "completed"; /** Execution hit a terminal error or maximum retry cap. */
1146
+ readonly error: "error"; /** Upload was canceled by the user. */
1147
+ readonly canceled: "canceled";
1148
+ };
1149
+ /** Every upload phase; the `phase` discriminator of {@link Item}. */
1150
+ export type Phase = keyof typeof Phases;
1151
+ interface BaseItem<P extends string> {
1152
+ /** Unique client-side identifier for this file item. */
1153
+ localId: string;
1154
+ /** Target upload purpose. */
1155
+ purpose: P;
1156
+ /** Metadata properties identifying the file. */
1157
+ fingerprint: Contracts.FingerprintFile;
1158
+ /** Epoch timestamp in ms when the item was registered. */
1159
+ createdAt: number;
1160
+ attempt?: number | undefined;
1161
+ file?: File | undefined;
1162
+ /** Full phase history. Each entry records when a phase was entered/left and any stripped error. */
1163
+ steps: Contracts.UploadStep[];
1164
+ /** Arbitrary caller-supplied metadata from the addFiles command. Never persisted. */
1165
+ meta: Record<string, unknown>;
1166
+ }
1167
+ /**
1168
+ * Representational union of upload items in their respective lifecycle phases.
1169
+ */
1170
+ export type Item<M extends Contracts.Intent.Map, C extends Contracts.Cursor.Map<M>, P extends string, R extends Contracts.Result.Base = Contracts.Result.Base> = BaseItem<P> & ({
1171
+ phase: 'validating';
1172
+ file: File;
1173
+ } | {
1174
+ phase: 'creating_intent';
1175
+ file: File;
1176
+ attempt: number;
1177
+ } | {
1178
+ phase: 'ready';
1179
+ file: File;
1180
+ intent: Contracts.Intent.Any<M>;
1181
+ cursor?: Contracts.Cursor.Any<C> | undefined;
1182
+ progress?: Progress | undefined;
1183
+ } | {
1184
+ phase: 'queued';
1185
+ file: File;
1186
+ intent: Contracts.Intent.Any<M>;
1187
+ requestedAt: number;
1188
+ cursor?: Contracts.Cursor.Any<C> | undefined;
1189
+ progress?: Progress | undefined;
1190
+ } | {
1191
+ phase: 'uploading';
1192
+ file: File;
1193
+ intent: Contracts.Intent.Any<M>;
1194
+ startedAt: number;
1195
+ progress: Progress;
1196
+ cursor?: Contracts.Cursor.Any<C> | undefined;
1197
+ } | {
1198
+ phase: 'paused';
1199
+ intent: Contracts.Intent.Any<M>;
1200
+ cursor: Contracts.Cursor.Any<C>;
1201
+ progress: Progress;
1202
+ pausedAt: number;
1203
+ file?: File | undefined;
1204
+ } | {
1205
+ phase: 'completing';
1206
+ file: File;
1207
+ intent: Contracts.Intent.Any<M>;
1208
+ progress: Progress;
1209
+ completingAt: number;
1210
+ } | {
1211
+ phase: 'completed';
1212
+ completedBy: CompletionKind;
1213
+ result: R;
1214
+ completedAt: number;
1215
+ intent?: Contracts.Intent.Any<M> | undefined;
1216
+ file?: File | undefined;
1217
+ } | {
1218
+ phase: 'error';
1219
+ error: UploadError;
1220
+ retryable: boolean;
1221
+ attempt: number;
1222
+ failedAt: number;
1223
+ file?: File | undefined;
1224
+ intent?: Contracts.Intent.Any<M> | undefined;
1225
+ cursor?: Contracts.Cursor.Any<C> | undefined;
1226
+ progress?: Progress | undefined;
1227
+ } | {
1228
+ phase: 'canceled';
1229
+ canceledAt: number;
1230
+ file?: File | undefined;
1231
+ intent?: Contracts.Intent.Any<M> | undefined;
1232
+ cursor?: Contracts.Cursor.Any<C> | undefined;
1233
+ progress?: Progress | undefined;
1234
+ attempt?: number | undefined;
1235
+ });
1236
+ /**
1237
+ * Immutable state shape of the upload engine store.
1238
+ */
1239
+ export type State<M extends Contracts.Intent.Map, C extends Contracts.Cursor.Map<M>, P extends string, R extends Contracts.Result.Base = Contracts.Result.Base> = {
1240
+ /** Map of active and historical upload items. */items: Map<string, Item<M, C, P, R>>;
1241
+ };
1242
+ /**
1243
+ * Interface for registering lifecycle plugins.
1244
+ */
1245
+ export type Plugin<M extends Contracts.Intent.Map, C extends Contracts.Cursor.Map<M>, P extends string, R extends Contracts.Result.Base = Contracts.Result.Base> = {
1246
+ /** Name of the plugin (for diagnostics). */name: string; /** Sets up subscription listener binds on the store core proxy. */
1247
+ setup(store: Pick<Store.UploadStore<M, C, P, R>, 'on' | 'off' | 'dispatch' | 'getSnapshot'>): void;
1248
+ };
1249
+ /**
1250
+ * Events emitted by effects and consumed by the reducer to transition item states.
1251
+ */
1252
+ export type Event<M extends Contracts.Intent.Map, C extends Contracts.Cursor.Map<M>, P extends string, R extends Contracts.Result.Base = Contracts.Result.Base> = {
1253
+ type: 'files.added';
1254
+ items: Array<{
1255
+ localId: string;
1256
+ purpose: P;
1257
+ file: File;
1258
+ fingerprint: Contracts.FingerprintFile;
1259
+ createdAt: number;
1260
+ meta: Record<string, unknown>;
1261
+ }>;
1262
+ } | {
1263
+ type: 'fingerprint.updated';
1264
+ localId: string;
1265
+ fingerprint: Contracts.FingerprintFile;
1266
+ } | {
1267
+ type: 'validation.ok';
1268
+ localId: string;
1269
+ } | {
1270
+ type: 'validation.failed';
1271
+ localId: string;
1272
+ reason: Contracts.Validation.Rejection;
1273
+ } | {
1274
+ type: 'intent.ok';
1275
+ localId: string;
1276
+ intent: Contracts.Intent.Any<M>;
1277
+ } | {
1278
+ type: 'intent.failed';
1279
+ localId: string;
1280
+ error: UploadError;
1281
+ retryable: boolean;
1282
+ } | {
1283
+ type: 'upload.begin';
1284
+ localId: string;
1285
+ startedAt: number;
1286
+ } | {
1287
+ type: 'upload.progress';
1288
+ localId: string;
1289
+ uploadedBytes: number;
1290
+ totalBytes: number;
1291
+ } | {
1292
+ type: 'cursor.updated';
1293
+ localId: string;
1294
+ cursor: Contracts.Cursor.Any<C>;
1295
+ } | {
1296
+ type: 'upload.ok';
1297
+ localId: string;
1298
+ } | {
1299
+ type: 'upload.failed';
1300
+ localId: string;
1301
+ error: UploadError;
1302
+ retryable: boolean;
1303
+ } | {
1304
+ type: 'dedupe.ok';
1305
+ localId: string;
1306
+ result: R;
1307
+ } | {
1308
+ type: 'complete.ok';
1309
+ localId: string;
1310
+ result: R;
1311
+ } | {
1312
+ type: 'complete.failed';
1313
+ localId: string;
1314
+ error: UploadError;
1315
+ retryable: boolean;
1316
+ } | {
1317
+ type: 'paused';
1318
+ localId: string;
1319
+ cursor: Contracts.Cursor.Any<C>;
1320
+ pausedAt: number;
1321
+ } | {
1322
+ type: 'canceled';
1323
+ localId: string;
1324
+ canceledAt: number;
1325
+ };
1326
+ /**
1327
+ * Public event registry mapping event names to payloads emitted via `store.on()`.
1328
+ */
1329
+ export type EventMap<M extends Contracts.Intent.Map, C extends Contracts.Cursor.Map<M>, P extends string, R extends Contracts.Result.Base = Contracts.Result.Base> = {
1330
+ /** Emitted when a file is validated and successfully registered in state. */'file.added': {
1331
+ localId: string;
1332
+ purpose: P;
1333
+ file: File;
1334
+ fingerprint: Contracts.FingerprintFile;
1335
+ }; /** Emitted when a file fails client-side validation rules. */
1336
+ 'file.rejected': {
1337
+ file: File;
1338
+ reason: Contracts.Validation.Rejection;
1339
+ }; /** Emitted when validation succeeds. */
1340
+ 'validation.ok': {
1341
+ localId: string;
1342
+ }; /** Emitted when validation fails. */
1343
+ 'validation.failed': {
1344
+ localId: string;
1345
+ reason: Contracts.Validation.Rejection;
1346
+ }; /** Emitted when intent lookup/creation is requested. */
1347
+ 'intent.creating': {
1348
+ localId: string;
1349
+ }; /** Emitted when upload intent is successfully created. */
1350
+ 'intent.created': {
1351
+ localId: string;
1352
+ intent: M[keyof M];
1353
+ }; /** Emitted when intent creation fails. */
1354
+ 'intent.failed': {
1355
+ localId: string;
1356
+ error: UploadError;
1357
+ retryable: boolean;
1358
+ }; /** Emitted when an item is queued waiting for concurrency slots. */
1359
+ 'upload.queued': {
1360
+ localId: string;
1361
+ }; /** Emitted when a paused upload is resumed. */
1362
+ 'upload.resumed': {
1363
+ localId: string;
1364
+ }; /** Emitted when data transfer starts. */
1365
+ 'upload.started': {
1366
+ localId: string;
1367
+ }; /** Periodic progress event. */
1368
+ 'upload.progress': {
1369
+ localId: string;
1370
+ pct: number;
1371
+ uploadedBytes: number;
1372
+ totalBytes: number;
1373
+ }; /** Emitted when strategy cursor state is updated. */
1374
+ 'upload.cursor': {
1375
+ localId: string;
1376
+ cursor: Contracts.Cursor.Any<C>;
1377
+ }; /** Emitted when upload is paused. */
1378
+ 'upload.paused': {
1379
+ localId: string;
1380
+ cursor: Contracts.Cursor.Any<C>;
1381
+ }; /** Emitted when upload is canceled. */
1382
+ 'upload.canceled': {
1383
+ localId: string;
1384
+ }; /** Emitted when final completing steps (like completeMultipart or final verification) begin. */
1385
+ 'upload.completing': {
1386
+ localId: string;
1387
+ }; /** Emitted when a file is completely uploaded and finalized. */
1388
+ 'upload.completed': {
1389
+ localId: string;
1390
+ result: R;
1391
+ completedBy: CompletionKind;
1392
+ }; /** Emitted when transfer hits a retryable or terminal error. */
1393
+ 'upload.error': {
1394
+ localId: string;
1395
+ error: UploadError;
1396
+ retryable: boolean;
1397
+ }; /** Emitted when an item is removed from the store state. */
1398
+ 'upload.removed': {
1399
+ localId: string;
1400
+ reason: 'user' | 'cleanup';
1401
+ }; /** Emitted when a file rebind operation succeeds. */
1402
+ 'rebind.ok': {
1403
+ localId: string;
1404
+ }; /** Emitted when a file rebind fails. */
1405
+ 'rebind.failed': {
1406
+ localId: string;
1407
+ reason: RebindReason;
1408
+ };
1409
+ };
1410
+ /**
1411
+ * Rebind failure classifications.
1412
+ */
1413
+ export type RebindReason = {
1414
+ code: 'no_item';
1415
+ } | {
1416
+ code: 'wrong_phase';
1417
+ phase: string;
1418
+ } | {
1419
+ code: 'already_bound';
1420
+ } | {
1421
+ code: 'fingerprint_mismatch';
1422
+ expected: Contracts.FingerprintFile;
1423
+ got: Contracts.FingerprintFile;
1424
+ };
1425
+ /**
1426
+ * Diagnostic hooks for observing engine updates.
1427
+ */
1428
+ export type Hooks<M extends Contracts.Intent.Map, C extends Contracts.Cursor.Map<M>, P extends string, R extends Contracts.Result.Base = Contracts.Result.Base> = {
1429
+ /** Callback invoked on every state-reducing internal event. */onInternalEvent?: (event: Event<M, C, P, R>, state: State<M, C, P, R>) => void;
1430
+ };
1431
+ export {};
1432
+ }
1433
+ //#endregion
1434
+ //#region src/core/engine/engine.libs.d.ts
1435
+ /**
1436
+ * Normalizes user config by applying sensible defaults.
1437
+ * @author wildduck2 <https://github.com/wildduck2>
1438
+ */
1439
+ declare function resolveUploadConfig<P extends string>(input?: Partial<Engine.Config<P>>): Engine.Config<P>;
1440
+ //#endregion
1441
+ export { UploadUnknownError as C, Transport as D, createXHRTransport as E, Contracts as O, UploadTimeoutError as S, createFetchTransport as T, UploadHttpError as _, deserializeSnapshot as a, UploadServerError as b, createMemoryAdapter as c, UploadPersistence as d, UploadAbortError as f, UploadErrorContext as g, UploadError as h, Store as i, LocalStorageAdapter as l, UploadEngineError as m, Engine as n, serializeSnapshot as o, UploadAuthError as p, createUploadStore as r, MemoryAdapter as s, resolveUploadConfig as t, IndexedDBAdapter as u, UploadNetworkError as v, UploadValidationError as w, UploadStrategyMissingError as x, UploadRateLimitError as y };