@gentleduck/upload 0.2.2 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/async-DxRWu4le.js +1 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.js +1 -0
- package/dist/core-BNxznRif.js +2 -0
- package/dist/index-BXg9WIce.d.ts +987 -0
- package/dist/index.d.ts +5 -1417
- package/dist/index.js +1 -6
- package/dist/react/index.d.ts +90 -0
- package/dist/react/index.js +1 -0
- package/dist/strategies/index.d.ts +56 -0
- package/dist/strategies/index.js +1 -0
- package/dist/strategy.types-gg9ZStRe.d.ts +225 -0
- package/package.json +26 -13
- package/src/core/engine/store/handlers/clean-up.ts +1 -1
- package/src/core/engine/store/store.dispatch.ts +9 -3
- package/src/core/engine/store/store.runtime.ts +3 -1
- package/src/core/engine/store/store.types.ts +1 -1
- package/src/core/engine/validation/file.ts +1 -1
- package/src/core/persistence/persistence.ts +6 -1
- package/src/core/utils/emitter/index.ts +6 -1
- package/src/react/upload-provider.tsx +27 -2
- package/src/react/use-uploader.tsx +25 -4
- package/src/strategies/multipart/index.ts +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,1417 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* Base shape for all upload intents.
|
|
7
|
-
*
|
|
8
|
-
* An "intent" is data provided by your backend that tells the client how to upload a file
|
|
9
|
-
* (for example: a presigned POST, presigned PUT, multipart upload IDs, part URLs, headers, etc).
|
|
10
|
-
*
|
|
11
|
-
* Every intent must include:
|
|
12
|
-
* - `strategy`: a discriminant used to select an upload strategy implementation
|
|
13
|
-
* - `fileId`: a stable backend identifier for the file being uploaded
|
|
14
|
-
*
|
|
15
|
-
* @typeParam K - Strategy key / discriminant string (example: `"direct" | "multipart"`).
|
|
16
|
-
*/
|
|
17
|
-
type IntentBase<K$1 extends string = string> = {
|
|
18
|
-
/** Strategy name (discriminant). */
|
|
19
|
-
strategy: K$1;
|
|
20
|
-
/** Unique backend file identifier. */
|
|
21
|
-
fileId: string;
|
|
22
|
-
};
|
|
23
|
-
/**
|
|
24
|
-
* Registry of intent types mapped by strategy name.
|
|
25
|
-
*
|
|
26
|
-
* Example:
|
|
27
|
-
* ```ts
|
|
28
|
-
* type MyIntents = {
|
|
29
|
-
* direct: DirectIntent
|
|
30
|
-
* multipart: MultipartIntent
|
|
31
|
-
* }
|
|
32
|
-
* ```
|
|
33
|
-
*
|
|
34
|
-
* `M[keyof M]` is used throughout the engine as the "any intent" union.
|
|
35
|
-
*/
|
|
36
|
-
type IntentMap = Record<string, IntentBase<string>>;
|
|
37
|
-
/** Union of strategy keys for an intent map. */
|
|
38
|
-
type StrategyKey<M extends IntentMap> = keyof M & string;
|
|
39
|
-
/** Union of all intent variants for an intent map. */
|
|
40
|
-
type AnyIntent<M extends IntentMap> = M[StrategyKey<M>];
|
|
41
|
-
//#endregion
|
|
42
|
-
//#region src/core/contracts/result.types.d.ts
|
|
43
|
-
/**
|
|
44
|
-
* Base shape for upload completion results returned by your backend.
|
|
45
|
-
*
|
|
46
|
-
* Extend this with any additional metadata you return (e.g. width/height, variants).
|
|
47
|
-
*/
|
|
48
|
-
type UploadResultBase = {
|
|
49
|
-
/** Backend file identifier. */
|
|
50
|
-
fileId: string;
|
|
51
|
-
/** Storage key or path used for signed URLs. */
|
|
52
|
-
key: string;
|
|
53
|
-
};
|
|
54
|
-
//#endregion
|
|
55
|
-
//#region src/core/contracts/backendApi.d.ts
|
|
56
|
-
type WithSignal = {
|
|
57
|
-
signal?: AbortSignal;
|
|
58
|
-
};
|
|
59
|
-
interface UploadApi<M extends IntentMap, P extends string, R extends UploadResultBase = UploadResultBase> {
|
|
60
|
-
createIntent(args: {
|
|
61
|
-
purpose: P;
|
|
62
|
-
contentType: string;
|
|
63
|
-
size: number;
|
|
64
|
-
filename: string;
|
|
65
|
-
checksum?: string;
|
|
66
|
-
}, opts?: WithSignal): Promise<M[keyof M]>;
|
|
67
|
-
complete(args: {
|
|
68
|
-
fileId: string;
|
|
69
|
-
}, opts?: WithSignal): Promise<R>;
|
|
70
|
-
getSignedPreviewUrl?(args: {
|
|
71
|
-
fileId: string;
|
|
72
|
-
key: string;
|
|
73
|
-
purpose: P;
|
|
74
|
-
}, opts?: WithSignal): Promise<string>;
|
|
75
|
-
/**
|
|
76
|
-
* Optional support for finding existing files by checksum for deduplication.
|
|
77
|
-
* If implemented, the upload engine will check for existing files before uploading.
|
|
78
|
-
* If a file with the same checksum exists, the upload will be skipped and the existing file will be linked.
|
|
79
|
-
*/
|
|
80
|
-
findByChecksum?(args: {
|
|
81
|
-
checksum: string;
|
|
82
|
-
purpose: P;
|
|
83
|
-
}, opts?: WithSignal): Promise<R | null>;
|
|
84
|
-
multipart?: {
|
|
85
|
-
signPart(args: {
|
|
86
|
-
fileId: string;
|
|
87
|
-
uploadId: string;
|
|
88
|
-
partNumber: number;
|
|
89
|
-
checksum?: string;
|
|
90
|
-
}, opts?: WithSignal): Promise<{
|
|
91
|
-
url: string;
|
|
92
|
-
headers?: Record<string, string>;
|
|
93
|
-
}>;
|
|
94
|
-
completeMultipart(args: {
|
|
95
|
-
fileId: string;
|
|
96
|
-
uploadId: string;
|
|
97
|
-
parts: Array<{
|
|
98
|
-
partNumber: number;
|
|
99
|
-
etag: string;
|
|
100
|
-
}>;
|
|
101
|
-
}, opts?: WithSignal): Promise<unknown>;
|
|
102
|
-
listParts?(args: {
|
|
103
|
-
fileId: string;
|
|
104
|
-
uploadId: string;
|
|
105
|
-
}, opts?: WithSignal): Promise<Array<{
|
|
106
|
-
partNumber: number;
|
|
107
|
-
etag?: string;
|
|
108
|
-
size?: number;
|
|
109
|
-
}>>;
|
|
110
|
-
abort?(args: {
|
|
111
|
-
fileId: string;
|
|
112
|
-
uploadId: string;
|
|
113
|
-
}, opts?: WithSignal): Promise<void>;
|
|
114
|
-
};
|
|
115
|
-
tus?: {
|
|
116
|
-
create(args: {
|
|
117
|
-
fileId: string;
|
|
118
|
-
size: number;
|
|
119
|
-
filename: string;
|
|
120
|
-
contentType: string;
|
|
121
|
-
}, opts?: WithSignal): Promise<{
|
|
122
|
-
uploadUrl: string;
|
|
123
|
-
}>;
|
|
124
|
-
getOffset(args: {
|
|
125
|
-
uploadUrl: string;
|
|
126
|
-
}, opts?: WithSignal): Promise<{
|
|
127
|
-
offset: number;
|
|
128
|
-
}>;
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
//#endregion
|
|
132
|
-
//#region src/core/contracts/cursor.types.d.ts
|
|
133
|
-
/**
|
|
134
|
-
* Registry of cursor payload types mapped by strategy name.
|
|
135
|
-
*
|
|
136
|
-
* A "cursor" is strategy-defined resume state (ex: multipart uploaded parts, next byte offset).
|
|
137
|
-
* Use `unknown` here and define concrete cursor payload types in your app.
|
|
138
|
-
*
|
|
139
|
-
* @typeParam M - The intent map, used to constrain strategy keys.
|
|
140
|
-
*/
|
|
141
|
-
type CursorMap<M extends IntentMap> = Partial<Record<StrategyKey<M>, unknown>>;
|
|
142
|
-
/**
|
|
143
|
-
* Discriminated union of all cursor variants.
|
|
144
|
-
*
|
|
145
|
-
* The cursor is always tagged with a `strategy` so it can be routed back to the correct strategy
|
|
146
|
-
* on resume/rebind.
|
|
147
|
-
*
|
|
148
|
-
* @typeParam C - Cursor registry (usually {@link CursorMap}).
|
|
149
|
-
*/
|
|
150
|
-
type AnyCursor<C extends Record<string, unknown>> = { [K in keyof C & string]: {
|
|
151
|
-
strategy: K;
|
|
152
|
-
value?: C[K];
|
|
153
|
-
} }[keyof C & string];
|
|
154
|
-
//#endregion
|
|
155
|
-
//#region src/core/contracts/errors.types.d.ts
|
|
156
|
-
/**
|
|
157
|
-
* File rejection reasons produced by client-side validation.
|
|
158
|
-
*
|
|
159
|
-
* These should be safe to show in UI.
|
|
160
|
-
*/
|
|
161
|
-
type RejectReason = {
|
|
162
|
-
code: 'empty_file';
|
|
163
|
-
} | {
|
|
164
|
-
code: 'file_too_large';
|
|
165
|
-
maxBytes: number;
|
|
166
|
-
size: number;
|
|
167
|
-
} | {
|
|
168
|
-
code: 'type_not_allowed';
|
|
169
|
-
allowed: string[];
|
|
170
|
-
got: string;
|
|
171
|
-
} | {
|
|
172
|
-
code: 'too_many_files';
|
|
173
|
-
max: number;
|
|
174
|
-
};
|
|
175
|
-
/**
|
|
176
|
-
* Base interface for custom errors.
|
|
177
|
-
*
|
|
178
|
-
* If you want to add domain-specific fields, extend this and intersect in {@link UploadError}.
|
|
179
|
-
*/
|
|
180
|
-
interface UploadErrorBase {
|
|
181
|
-
/** Stable error code. */
|
|
182
|
-
code: string;
|
|
183
|
-
/** Human-friendly message (safe for UI). */
|
|
184
|
-
message: string;
|
|
185
|
-
/** Optional cause (original error, response, etc). */
|
|
186
|
-
cause?: unknown;
|
|
187
|
-
/** Whether the error should be retried. */
|
|
188
|
-
retryable?: boolean;
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* Built-in engine errors.
|
|
192
|
-
*
|
|
193
|
-
* Keep these narrow and explicit so reducer logic can rely on `code` as a discriminant.
|
|
194
|
-
*/
|
|
195
|
-
type BuiltInUploadError = {
|
|
196
|
-
code: 'validation_failed';
|
|
197
|
-
message: string;
|
|
198
|
-
reason: RejectReason;
|
|
199
|
-
retryable?: false;
|
|
200
|
-
} | {
|
|
201
|
-
code: 'strategy_missing';
|
|
202
|
-
message: string;
|
|
203
|
-
strategy: string;
|
|
204
|
-
retryable?: false;
|
|
205
|
-
} | {
|
|
206
|
-
code: 'aborted';
|
|
207
|
-
message: string;
|
|
208
|
-
reason: 'pause' | 'cancel' | 'unknown';
|
|
209
|
-
cause?: unknown;
|
|
210
|
-
retryable?: false;
|
|
211
|
-
} | {
|
|
212
|
-
code: 'network';
|
|
213
|
-
message: string;
|
|
214
|
-
cause?: unknown;
|
|
215
|
-
retryable?: boolean;
|
|
216
|
-
} | {
|
|
217
|
-
code: 'http';
|
|
218
|
-
message: string;
|
|
219
|
-
status: number;
|
|
220
|
-
statusText?: string;
|
|
221
|
-
cause?: unknown;
|
|
222
|
-
retryable?: boolean;
|
|
223
|
-
} | {
|
|
224
|
-
code: 'timeout';
|
|
225
|
-
message: string;
|
|
226
|
-
cause?: unknown;
|
|
227
|
-
retryable?: boolean;
|
|
228
|
-
} | {
|
|
229
|
-
code: 'auth';
|
|
230
|
-
message: string;
|
|
231
|
-
cause?: unknown;
|
|
232
|
-
retryable?: false;
|
|
233
|
-
} | {
|
|
234
|
-
code: 'rate_limit';
|
|
235
|
-
message: string;
|
|
236
|
-
retryAfterMs?: number;
|
|
237
|
-
cause?: unknown;
|
|
238
|
-
retryable?: boolean;
|
|
239
|
-
} | {
|
|
240
|
-
code: 'server';
|
|
241
|
-
message: string;
|
|
242
|
-
serverCode?: string;
|
|
243
|
-
cause?: unknown;
|
|
244
|
-
retryable?: boolean;
|
|
245
|
-
} | {
|
|
246
|
-
code: 'unknown';
|
|
247
|
-
message: string;
|
|
248
|
-
cause?: unknown;
|
|
249
|
-
retryable?: boolean;
|
|
250
|
-
};
|
|
251
|
-
/**
|
|
252
|
-
* The error type used everywhere in the engine.
|
|
253
|
-
*
|
|
254
|
-
* You can extend this by intersecting your own shape with {@link UploadErrorBase}
|
|
255
|
-
* to add fields (example: `{ endpoint: string }`).
|
|
256
|
-
*/
|
|
257
|
-
type UploadError = BuiltInUploadError | (UploadErrorBase & Record<string, unknown>);
|
|
258
|
-
/**
|
|
259
|
-
* Validation rules applied on `addFiles` before an item enters the upload pipeline.
|
|
260
|
-
*/
|
|
261
|
-
type UploadValidationRules = {
|
|
262
|
-
/** Maximum number of files allowed. */
|
|
263
|
-
maxFiles?: number;
|
|
264
|
-
/** Maximum file size in bytes. */
|
|
265
|
-
maxSizeBytes?: number;
|
|
266
|
-
/** Minimum file size in bytes. */
|
|
267
|
-
minSizeBytes?: number;
|
|
268
|
-
/** Allowed MIME types. */
|
|
269
|
-
allowedTypes?: string[];
|
|
270
|
-
/** Allowed file extensions. */
|
|
271
|
-
allowedExtensions?: string[];
|
|
272
|
-
};
|
|
273
|
-
//#endregion
|
|
274
|
-
//#region src/core/contracts/fingerprint.types.d.ts
|
|
275
|
-
/**
|
|
276
|
-
* Deterministic client-side identity for a file.
|
|
277
|
-
*
|
|
278
|
-
* Used to match the same file across refreshes (for rebind) and to deduplicate.
|
|
279
|
-
* If you include `checksum`, it should be stable and computed consistently.
|
|
280
|
-
*/
|
|
281
|
-
type FileFingerprint = {
|
|
282
|
-
/** File name. */
|
|
283
|
-
name: string;
|
|
284
|
-
/** File size in bytes. */
|
|
285
|
-
size: number;
|
|
286
|
-
/** File MIME type. */
|
|
287
|
-
type: string;
|
|
288
|
-
/** File lastModified timestamp (ms). */
|
|
289
|
-
lastModified: number;
|
|
290
|
-
/** Optional checksum (example: SHA-256 hex). */
|
|
291
|
-
checksum?: string;
|
|
292
|
-
};
|
|
293
|
-
//#endregion
|
|
294
|
-
//#region src/core/contracts/transport/transport.types.d.ts
|
|
295
|
-
/**
|
|
296
|
-
* Abstraction layer for network operations.
|
|
297
|
-
* Allows switching between XHR (browser) or other implementations (testing/Node).
|
|
298
|
-
*
|
|
299
|
-
* Designed to support:
|
|
300
|
-
* - Deterministic progress tracking (requires XHR in browsers)
|
|
301
|
-
* - Cancellation via AbortSignal
|
|
302
|
-
* - Header parsing (ETag extraction)
|
|
303
|
-
*/
|
|
304
|
-
interface UploadTransport {
|
|
305
|
-
/**
|
|
306
|
-
* Performs an HTTP PUT request (typically for S3 signed URLs).
|
|
307
|
-
*/
|
|
308
|
-
put(args: {
|
|
309
|
-
url: string;
|
|
310
|
-
body: Blob;
|
|
311
|
-
headers?: Record<string, string>;
|
|
312
|
-
signal: AbortSignal;
|
|
313
|
-
onProgress?: (u: number, t: number) => void;
|
|
314
|
-
}): Promise<{
|
|
315
|
-
etag?: string;
|
|
316
|
-
headers?: Record<string, string>;
|
|
317
|
-
}>;
|
|
318
|
-
/**
|
|
319
|
-
* Performs an HTTP POST multipart request.
|
|
320
|
-
*/
|
|
321
|
-
postForm(args: {
|
|
322
|
-
url: string;
|
|
323
|
-
fields: Record<string, string>;
|
|
324
|
-
file: File | Blob;
|
|
325
|
-
filename?: string;
|
|
326
|
-
signal: AbortSignal;
|
|
327
|
-
onProgress?: (uploadedBytes: number, totalBytes: number) => void;
|
|
328
|
-
}): Promise<{
|
|
329
|
-
etag?: string;
|
|
330
|
-
headers?: Record<string, string>;
|
|
331
|
-
}>;
|
|
332
|
-
/**
|
|
333
|
-
* Performs an HTTP request.
|
|
334
|
-
*/
|
|
335
|
-
patch(args: {
|
|
336
|
-
url: string;
|
|
337
|
-
body: Blob | ArrayBuffer;
|
|
338
|
-
headers?: Record<string, string>;
|
|
339
|
-
signal: AbortSignal;
|
|
340
|
-
onProgress?: (u: number, t: number) => void;
|
|
341
|
-
}): Promise<{
|
|
342
|
-
headers?: Record<string, string>;
|
|
343
|
-
}>;
|
|
344
|
-
}
|
|
345
|
-
//#endregion
|
|
346
|
-
//#region src/core/contracts/strategy.types.d.ts
|
|
347
|
-
type StrategyCtx<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase, K$1 extends keyof M & string> = {
|
|
348
|
-
file: File;
|
|
349
|
-
intent: M[K$1];
|
|
350
|
-
signal: AbortSignal;
|
|
351
|
-
transport: UploadTransport;
|
|
352
|
-
api: UploadApi<M, P, R>;
|
|
353
|
-
reportProgress: (p: {
|
|
354
|
-
uploadedBytes: number;
|
|
355
|
-
totalBytes: number;
|
|
356
|
-
}) => void;
|
|
357
|
-
readCursor: () => C[K$1] | undefined;
|
|
358
|
-
persistCursor: (cursor: C[K$1] | undefined) => void;
|
|
359
|
-
};
|
|
360
|
-
type UploadStrategy<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase, K$1 extends keyof M & string> = {
|
|
361
|
-
id: K$1;
|
|
362
|
-
resumable: boolean;
|
|
363
|
-
start(ctx: StrategyCtx<M, C, P, R, K$1>): Promise<void>;
|
|
364
|
-
};
|
|
365
|
-
interface StrategyRegistry<M extends IntentMap, C extends CursorMap<M>, P extends string = string, R extends UploadResultBase = UploadResultBase> {
|
|
366
|
-
get<K$1 extends keyof M & string>(id: K$1): UploadStrategy<M, C, P, R, K$1> | undefined;
|
|
367
|
-
has(id: string): id is keyof M & string;
|
|
368
|
-
set<K$1 extends keyof M & string>(strategy: UploadStrategy<M, C, P, R, K$1>): void;
|
|
369
|
-
}
|
|
370
|
-
//#endregion
|
|
371
|
-
//#region src/core/contracts/transport/transport.d.ts
|
|
372
|
-
type XhrCommonArgs = {
|
|
373
|
-
url: string;
|
|
374
|
-
signal?: AbortSignal;
|
|
375
|
-
headers?: Record<string, string>;
|
|
376
|
-
onProgress?: (loaded: number, total: number) => void;
|
|
377
|
-
};
|
|
378
|
-
/**
|
|
379
|
-
* Creates a browser-native XHR transport.
|
|
380
|
-
* We use XMLHttpRequest instead of fetch because fetch does not yet support
|
|
381
|
-
* upload progress events in a standard cross-browser way.
|
|
382
|
-
*/
|
|
383
|
-
declare function createXHRTransport(): UploadTransport & {
|
|
384
|
-
patch?: (args: XhrCommonArgs & {
|
|
385
|
-
body: Blob | ArrayBuffer;
|
|
386
|
-
}) => Promise<{
|
|
387
|
-
headers: Record<string, string>;
|
|
388
|
-
}>;
|
|
389
|
-
};
|
|
390
|
-
//#endregion
|
|
391
|
-
//#region src/core/client/retry.types.d.ts
|
|
392
|
-
/**
|
|
393
|
-
* Output of the retry policy.
|
|
394
|
-
*
|
|
395
|
-
* `delayMs` should be a backoff delay before re-attempting the failed step.
|
|
396
|
-
*/
|
|
397
|
-
type RetryDecision = {
|
|
398
|
-
retryable: false;
|
|
399
|
-
} | {
|
|
400
|
-
retryable: true;
|
|
401
|
-
delayMs: number;
|
|
402
|
-
};
|
|
403
|
-
//#endregion
|
|
404
|
-
//#region src/core/client/config.types.d.ts
|
|
405
|
-
/**
|
|
406
|
-
* Global upload engine configuration.
|
|
407
|
-
*
|
|
408
|
-
* @typeParam P - Union of allowed `purpose` strings for your app.
|
|
409
|
-
*/
|
|
410
|
-
type UploadConfig<P extends string> = {
|
|
411
|
-
/** Maximum concurrent uploads. */
|
|
412
|
-
maxConcurrentUploads: number;
|
|
413
|
-
/**
|
|
414
|
-
* Auto-start uploads for specific purposes.
|
|
415
|
-
* - Array form: only those purposes auto-start
|
|
416
|
-
* - Function form: dynamic decision per purpose
|
|
417
|
-
*/
|
|
418
|
-
autoStart?: readonly P[] | ((purpose: P) => boolean);
|
|
419
|
-
/** Progress event throttle in milliseconds. */
|
|
420
|
-
progressThrottleMs: number;
|
|
421
|
-
/** Validation rules keyed by purpose. */
|
|
422
|
-
validation: Partial<Record<P, UploadValidationRules>>;
|
|
423
|
-
/** Maximum number of retry attempts (per item / per phase depending on implementation). */
|
|
424
|
-
maxAttempts: number;
|
|
425
|
-
/**
|
|
426
|
-
* Retry policy.
|
|
427
|
-
* Called whenever a phase fails and the engine needs a decision.
|
|
428
|
-
*/
|
|
429
|
-
retryPolicy?: (ctx: {
|
|
430
|
-
phase: 'intent' | 'upload' | 'complete';
|
|
431
|
-
attempt: number;
|
|
432
|
-
error: UploadError;
|
|
433
|
-
}) => RetryDecision;
|
|
434
|
-
/**
|
|
435
|
-
* Maximum number of items to keep in state.
|
|
436
|
-
* When exceeded, oldest completed/canceled items are removed automatically.
|
|
437
|
-
*
|
|
438
|
-
* Set to `undefined` for no limit (not recommended for long-running apps).
|
|
439
|
-
* Default often: `100`.
|
|
440
|
-
*/
|
|
441
|
-
maxItems: number;
|
|
442
|
-
/**
|
|
443
|
-
* Automatically remove completed items after this many milliseconds.
|
|
444
|
-
* Set to `undefined` to keep completed items indefinitely.
|
|
445
|
-
*/
|
|
446
|
-
completedItemTTL?: number;
|
|
447
|
-
};
|
|
448
|
-
/**
|
|
449
|
-
* Config input shape accepted by store creation.
|
|
450
|
-
* All fields are optional; defaults are applied by {@link resolveUploadConfig}.
|
|
451
|
-
*/
|
|
452
|
-
type UploadConfigInput<P extends string> = Partial<UploadConfig<P>>;
|
|
453
|
-
/**
|
|
454
|
-
* Normalizes user config by applying sensible defaults.
|
|
455
|
-
*/
|
|
456
|
-
declare function resolveUploadConfig<P extends string>(input?: UploadConfigInput<P>): UploadConfig<P>;
|
|
457
|
-
//#endregion
|
|
458
|
-
//#region src/core/engine/commands.types.d.ts
|
|
459
|
-
/**
|
|
460
|
-
* Public commands accepted by the upload store.
|
|
461
|
-
*
|
|
462
|
-
* Reducer/effects should treat commands as "user intent".
|
|
463
|
-
*/
|
|
464
|
-
type UploadCommand<P extends string> = {
|
|
465
|
-
type: 'addFiles';
|
|
466
|
-
files: File[];
|
|
467
|
-
purpose: P;
|
|
468
|
-
} | {
|
|
469
|
-
type: 'start';
|
|
470
|
-
localId: string;
|
|
471
|
-
} | {
|
|
472
|
-
type: 'startAll';
|
|
473
|
-
purpose?: P;
|
|
474
|
-
} | {
|
|
475
|
-
type: 'pause';
|
|
476
|
-
localId: string;
|
|
477
|
-
} | {
|
|
478
|
-
type: 'pauseAll';
|
|
479
|
-
purpose?: P;
|
|
480
|
-
} | {
|
|
481
|
-
type: 'resume';
|
|
482
|
-
localId: string;
|
|
483
|
-
} | {
|
|
484
|
-
type: 'cancel';
|
|
485
|
-
localId: string;
|
|
486
|
-
} | {
|
|
487
|
-
type: 'cancelAll';
|
|
488
|
-
purpose?: P;
|
|
489
|
-
} | {
|
|
490
|
-
type: 'retry';
|
|
491
|
-
localId: string;
|
|
492
|
-
} | {
|
|
493
|
-
type: 'rebind';
|
|
494
|
-
localId: string;
|
|
495
|
-
file: File;
|
|
496
|
-
} | {
|
|
497
|
-
type: 'remove';
|
|
498
|
-
localId: string;
|
|
499
|
-
};
|
|
500
|
-
//#endregion
|
|
501
|
-
//#region src/core/engine/outcome.types.d.ts
|
|
502
|
-
type UploadCompletionKind = 'upload' | 'dedupe';
|
|
503
|
-
type UploadOutcome<R extends UploadResultBase> = {
|
|
504
|
-
localId: string;
|
|
505
|
-
status: 'completed';
|
|
506
|
-
completedBy: UploadCompletionKind;
|
|
507
|
-
result: R;
|
|
508
|
-
} | {
|
|
509
|
-
localId: string;
|
|
510
|
-
status: 'error';
|
|
511
|
-
error: UploadError;
|
|
512
|
-
} | {
|
|
513
|
-
localId: string;
|
|
514
|
-
status: 'canceled';
|
|
515
|
-
} | {
|
|
516
|
-
localId: string;
|
|
517
|
-
status: 'missing';
|
|
518
|
-
};
|
|
519
|
-
//#endregion
|
|
520
|
-
//#region src/core/engine/progress.types.d.ts
|
|
521
|
-
/**
|
|
522
|
-
* Upload progress snapshot.
|
|
523
|
-
*
|
|
524
|
-
* Invariants:
|
|
525
|
-
* - `totalBytes` should be `file.size` when known.
|
|
526
|
-
* - `pct` should be clamped to 0..100.
|
|
527
|
-
*/
|
|
528
|
-
type UploadProgress = {
|
|
529
|
-
/** Bytes uploaded so far. */
|
|
530
|
-
uploadedBytes: number;
|
|
531
|
-
/** Total bytes to upload. */
|
|
532
|
-
totalBytes: number;
|
|
533
|
-
/** Percent complete (0..100). */
|
|
534
|
-
pct: number;
|
|
535
|
-
};
|
|
536
|
-
//#endregion
|
|
537
|
-
//#region src/core/engine/internal-events.types.d.ts
|
|
538
|
-
/**
|
|
539
|
-
* Internal events emitted by effects and consumed by the reducer.
|
|
540
|
-
*
|
|
541
|
-
* These are not the same as public events. They are designed for correctness and state transitions.
|
|
542
|
-
*
|
|
543
|
-
* @typeParam M - Intent map
|
|
544
|
-
* @typeParam C - Cursor map
|
|
545
|
-
*/
|
|
546
|
-
type InternalEvent<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase = UploadResultBase> = {
|
|
547
|
-
type: 'files.added';
|
|
548
|
-
items: Array<{
|
|
549
|
-
localId: string;
|
|
550
|
-
purpose: P;
|
|
551
|
-
file: File;
|
|
552
|
-
fingerprint: FileFingerprint;
|
|
553
|
-
createdAt: number;
|
|
554
|
-
}>;
|
|
555
|
-
} | {
|
|
556
|
-
type: 'fingerprint.updated';
|
|
557
|
-
localId: string;
|
|
558
|
-
fingerprint: FileFingerprint;
|
|
559
|
-
} | {
|
|
560
|
-
type: 'validation.ok';
|
|
561
|
-
localId: string;
|
|
562
|
-
} | {
|
|
563
|
-
type: 'validation.failed';
|
|
564
|
-
localId: string;
|
|
565
|
-
reason: RejectReason;
|
|
566
|
-
} | {
|
|
567
|
-
type: 'intent.ok';
|
|
568
|
-
localId: string;
|
|
569
|
-
intent: AnyIntent<M>;
|
|
570
|
-
} | {
|
|
571
|
-
type: 'intent.failed';
|
|
572
|
-
localId: string;
|
|
573
|
-
error: UploadError;
|
|
574
|
-
retryable: boolean;
|
|
575
|
-
} | {
|
|
576
|
-
type: 'upload.begin';
|
|
577
|
-
localId: string;
|
|
578
|
-
startedAt: number;
|
|
579
|
-
} | {
|
|
580
|
-
type: 'upload.progress';
|
|
581
|
-
localId: string;
|
|
582
|
-
uploadedBytes: number;
|
|
583
|
-
totalBytes: number;
|
|
584
|
-
} | {
|
|
585
|
-
type: 'cursor.updated';
|
|
586
|
-
localId: string;
|
|
587
|
-
cursor: AnyCursor<C>;
|
|
588
|
-
} | {
|
|
589
|
-
type: 'upload.ok';
|
|
590
|
-
localId: string;
|
|
591
|
-
} | {
|
|
592
|
-
type: 'upload.failed';
|
|
593
|
-
localId: string;
|
|
594
|
-
error: UploadError;
|
|
595
|
-
retryable: boolean;
|
|
596
|
-
} | {
|
|
597
|
-
type: 'dedupe.ok';
|
|
598
|
-
localId: string;
|
|
599
|
-
result: R;
|
|
600
|
-
} | {
|
|
601
|
-
type: 'complete.ok';
|
|
602
|
-
localId: string;
|
|
603
|
-
result: R;
|
|
604
|
-
} | {
|
|
605
|
-
type: 'complete.failed';
|
|
606
|
-
localId: string;
|
|
607
|
-
error: UploadError;
|
|
608
|
-
retryable: boolean;
|
|
609
|
-
}
|
|
610
|
-
/** Internal completion for pause requests. */ | {
|
|
611
|
-
type: 'paused';
|
|
612
|
-
localId: string;
|
|
613
|
-
cursor: AnyCursor<C>;
|
|
614
|
-
pausedAt: number;
|
|
615
|
-
}
|
|
616
|
-
/** Internal completion for cancel requests. */ | {
|
|
617
|
-
type: 'canceled';
|
|
618
|
-
localId: string;
|
|
619
|
-
canceledAt: number;
|
|
620
|
-
};
|
|
621
|
-
/**
|
|
622
|
-
* All possible upload phases.
|
|
623
|
-
*
|
|
624
|
-
* Useful for constraints and UI filtering.
|
|
625
|
-
*/
|
|
626
|
-
type UploadPhase = 'validating' | 'creating_intent' | 'ready' | 'queued' | 'uploading' | 'paused' | 'completing' | 'completed' | 'error' | 'canceled';
|
|
627
|
-
/**
|
|
628
|
-
* State of a single upload item.
|
|
629
|
-
*
|
|
630
|
-
* This is a discriminated union on `phase`.
|
|
631
|
-
*
|
|
632
|
-
* @typeParam M - Intent map
|
|
633
|
-
* @typeParam C - Cursor map
|
|
634
|
-
* @typeParam P - Purpose union
|
|
635
|
-
*/
|
|
636
|
-
type UploadItem<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase = UploadResultBase> = {
|
|
637
|
-
/** Validating file against rules. */
|
|
638
|
-
phase: 'validating';
|
|
639
|
-
localId: string;
|
|
640
|
-
purpose: P;
|
|
641
|
-
fingerprint: FileFingerprint;
|
|
642
|
-
file: File;
|
|
643
|
-
createdAt: number;
|
|
644
|
-
} | {
|
|
645
|
-
/** Requesting upload intent from backend. */
|
|
646
|
-
phase: 'creating_intent';
|
|
647
|
-
localId: string;
|
|
648
|
-
purpose: P;
|
|
649
|
-
fingerprint: FileFingerprint;
|
|
650
|
-
file: File;
|
|
651
|
-
/** Current attempt number for this phase. */
|
|
652
|
-
attempt: number;
|
|
653
|
-
createdAt: number;
|
|
654
|
-
} | {
|
|
655
|
-
/** Intent received, ready to start upload. */
|
|
656
|
-
phase: 'ready';
|
|
657
|
-
localId: string;
|
|
658
|
-
purpose: P;
|
|
659
|
-
fingerprint: FileFingerprint;
|
|
660
|
-
file: File;
|
|
661
|
-
intent: AnyIntent<M>;
|
|
662
|
-
createdAt: number;
|
|
663
|
-
cursor?: AnyCursor<C>;
|
|
664
|
-
progress?: UploadProgress;
|
|
665
|
-
attempt?: number;
|
|
666
|
-
} | {
|
|
667
|
-
/** Queued for upload (waiting for slot). */
|
|
668
|
-
phase: 'queued';
|
|
669
|
-
localId: string;
|
|
670
|
-
purpose: P;
|
|
671
|
-
fingerprint: FileFingerprint;
|
|
672
|
-
file: File;
|
|
673
|
-
intent: AnyIntent<M>;
|
|
674
|
-
/** Timestamp when this item requested a concurrency slot. */
|
|
675
|
-
requestedAt: number;
|
|
676
|
-
createdAt: number;
|
|
677
|
-
cursor?: AnyCursor<C>;
|
|
678
|
-
progress?: UploadProgress;
|
|
679
|
-
attempt?: number;
|
|
680
|
-
} | {
|
|
681
|
-
/** Actively uploading bytes. */
|
|
682
|
-
phase: 'uploading';
|
|
683
|
-
localId: string;
|
|
684
|
-
purpose: P;
|
|
685
|
-
fingerprint: FileFingerprint;
|
|
686
|
-
file: File;
|
|
687
|
-
intent: AnyIntent<M>;
|
|
688
|
-
startedAt: number;
|
|
689
|
-
progress: UploadProgress;
|
|
690
|
-
createdAt: number;
|
|
691
|
-
cursor?: AnyCursor<C>;
|
|
692
|
-
attempt?: number;
|
|
693
|
-
} | {
|
|
694
|
-
/** Upload paused (resumable). */
|
|
695
|
-
phase: 'paused';
|
|
696
|
-
localId: string;
|
|
697
|
-
purpose: P;
|
|
698
|
-
fingerprint: FileFingerprint;
|
|
699
|
-
intent: AnyIntent<M>;
|
|
700
|
-
cursor: AnyCursor<C>;
|
|
701
|
-
progress: UploadProgress;
|
|
702
|
-
pausedAt: number;
|
|
703
|
-
createdAt: number;
|
|
704
|
-
/**
|
|
705
|
-
* File is optional because a paused item can be restored from persistence without a File.
|
|
706
|
-
* Use `rebind` to attach the File again before resuming (when required).
|
|
707
|
-
*/
|
|
708
|
-
file?: File;
|
|
709
|
-
attempt?: number;
|
|
710
|
-
} | {
|
|
711
|
-
/** Bytes sent, finalizing with backend. */
|
|
712
|
-
phase: 'completing';
|
|
713
|
-
localId: string;
|
|
714
|
-
purpose: P;
|
|
715
|
-
fingerprint: FileFingerprint;
|
|
716
|
-
file: File;
|
|
717
|
-
intent: AnyIntent<M>;
|
|
718
|
-
progress: UploadProgress;
|
|
719
|
-
completingAt: number;
|
|
720
|
-
createdAt: number;
|
|
721
|
-
attempt?: number;
|
|
722
|
-
} | {
|
|
723
|
-
/** Upload completed successfully. */
|
|
724
|
-
phase: 'completed';
|
|
725
|
-
localId: string;
|
|
726
|
-
file: File;
|
|
727
|
-
purpose: P;
|
|
728
|
-
fingerprint: FileFingerprint;
|
|
729
|
-
intent?: AnyIntent<M>;
|
|
730
|
-
completedBy: UploadCompletionKind;
|
|
731
|
-
result: R;
|
|
732
|
-
completedAt: number;
|
|
733
|
-
createdAt: number;
|
|
734
|
-
attempt?: number;
|
|
735
|
-
} | {
|
|
736
|
-
/** Upload failed (retryable or final). */
|
|
737
|
-
phase: 'error';
|
|
738
|
-
localId: string;
|
|
739
|
-
purpose: P;
|
|
740
|
-
fingerprint: FileFingerprint;
|
|
741
|
-
error: UploadError;
|
|
742
|
-
retryable: boolean;
|
|
743
|
-
attempt: number;
|
|
744
|
-
failedAt: number;
|
|
745
|
-
createdAt: number;
|
|
746
|
-
file?: File;
|
|
747
|
-
intent?: AnyIntent<M>;
|
|
748
|
-
cursor?: AnyCursor<C>;
|
|
749
|
-
progress?: UploadProgress;
|
|
750
|
-
} | {
|
|
751
|
-
/** Upload canceled by user/system. */
|
|
752
|
-
phase: 'canceled';
|
|
753
|
-
localId: string;
|
|
754
|
-
purpose: P;
|
|
755
|
-
fingerprint: FileFingerprint;
|
|
756
|
-
canceledAt: number;
|
|
757
|
-
createdAt: number;
|
|
758
|
-
file?: File;
|
|
759
|
-
intent?: AnyIntent<M>;
|
|
760
|
-
cursor?: AnyCursor<C>;
|
|
761
|
-
progress?: UploadProgress;
|
|
762
|
-
attempt?: number;
|
|
763
|
-
};
|
|
764
|
-
//#endregion
|
|
765
|
-
//#region src/core/engine/reducer.d.ts
|
|
766
|
-
type UploadState<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase = UploadResultBase> = {
|
|
767
|
-
/** Map of uploads by localId for O(1) lookups */
|
|
768
|
-
items: Map<string, UploadItem<M, C, P, R>>;
|
|
769
|
-
};
|
|
770
|
-
declare function createReducer<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase = UploadResultBase>(): (state: UploadState<M, C, P, R>, event: UploadCommand<P> | InternalEvent<M, C, P, R>) => UploadState<M, C, P, R>;
|
|
771
|
-
//#endregion
|
|
772
|
-
//#region src/core/persistence/persistence.types.d.ts
|
|
773
|
-
/**
|
|
774
|
-
* A minimal, serializable representation of an upload item that is safe to store
|
|
775
|
-
* in persistence (LocalStorage, IndexedDB, etc).
|
|
776
|
-
*
|
|
777
|
-
* This type is intentionally not the full {@link UploadItem} state.
|
|
778
|
-
* It captures only the fields needed to:
|
|
779
|
-
* - restore the UI list after refresh
|
|
780
|
-
* - rebind an upload to its backend intent (if already created)
|
|
781
|
-
* - resume an upload strategy from a known cursor (when supported)
|
|
782
|
-
* - restore last-known progress and phase for UX continuity
|
|
783
|
-
*
|
|
784
|
-
* @typeParam M - Map of upload intent variants keyed by intent kind (e.g. `direct`, `multipart`).
|
|
785
|
-
* @typeParam C - Map of cursor shapes keyed by {@link M}'s intent kinds.
|
|
786
|
-
* @typeParam P - Union of allowed `purpose` strings for your app (e.g. `"avatar" | "document"`).
|
|
787
|
-
*/
|
|
788
|
-
type PersistedSnapshot<M, C, P extends string> = {
|
|
789
|
-
/** Persistence schema version (not app version). */
|
|
790
|
-
version: number;
|
|
791
|
-
/** Unix epoch milliseconds when this snapshot was written. */
|
|
792
|
-
createdAt: number;
|
|
793
|
-
/** List of persisted upload items. */
|
|
794
|
-
items: Record<string, PersistedUploadItem<M, C, P>>;
|
|
795
|
-
};
|
|
796
|
-
type PersistedUploadItem<M, C, P extends string> = {
|
|
797
|
-
/** Stable, client-generated ID for this upload in local state. */
|
|
798
|
-
id: string;
|
|
799
|
-
/** File name. */
|
|
800
|
-
file: {
|
|
801
|
-
/** File name. */
|
|
802
|
-
name: string;
|
|
803
|
-
/** File size in bytes. */
|
|
804
|
-
size: number;
|
|
805
|
-
/** File MIME type. */
|
|
806
|
-
type: string;
|
|
807
|
-
/** File lastModified timestamp (ms). */
|
|
808
|
-
lastModified: number;
|
|
809
|
-
/** Optional checksum (example: SHA-256 hex). */
|
|
810
|
-
checksum?: string;
|
|
811
|
-
};
|
|
812
|
-
/** Backend-provided "intent" that describes how to upload (strategy, URLs, fields, etc). */
|
|
813
|
-
intent: M[keyof M];
|
|
814
|
-
/** Strategy cursor used to resume uploads that support continuation. */
|
|
815
|
-
cursor?: AnyCursor<C & Record<string, unknown>>;
|
|
816
|
-
/** Last-known progress for UX continuity after restoring from persistence. */
|
|
817
|
-
progress?: {
|
|
818
|
-
uploadedBytes: number;
|
|
819
|
-
totalBytes: number;
|
|
820
|
-
pct?: number;
|
|
821
|
-
};
|
|
822
|
-
/** The last known state-machine phase at the time of persistence. */
|
|
823
|
-
status: string;
|
|
824
|
-
/** Logical purpose for the upload (application-defined). */
|
|
825
|
-
purpose: P;
|
|
826
|
-
};
|
|
827
|
-
/**
|
|
828
|
-
* A persisted snapshot of the upload store.
|
|
829
|
-
*
|
|
830
|
-
* Snapshots are versioned to allow safe migrations when the persistence schema evolves.
|
|
831
|
-
* They are time-stamped for diagnostics and garbage-collection policies.
|
|
832
|
-
*/
|
|
833
|
-
interface PersistenceAdapter {
|
|
834
|
-
/** Loads a snapshot from persistence. */
|
|
835
|
-
load(key: string): unknown | null | Promise<unknown | null>;
|
|
836
|
-
/** Saves a snapshot to persistence. */
|
|
837
|
-
save(key: string, snapshot: unknown): void | Promise<void>;
|
|
838
|
-
/** Clears a snapshot from persistence. */
|
|
839
|
-
clear(key: string): void | Promise<void>;
|
|
840
|
-
}
|
|
841
|
-
//#endregion
|
|
842
|
-
//#region src/core/persistence/adapters.indexeddb.d.ts
|
|
843
|
-
declare const IndexedDBAdapter: PersistenceAdapter;
|
|
844
|
-
//#endregion
|
|
845
|
-
//#region src/core/persistence/adapters.local.d.ts
|
|
846
|
-
declare const LocalStorageAdapter: PersistenceAdapter;
|
|
847
|
-
//#endregion
|
|
848
|
-
//#region src/core/persistence/adapters.memory.d.ts
|
|
849
|
-
declare const MemoryAdapter: PersistenceAdapter;
|
|
850
|
-
//#endregion
|
|
851
|
-
//#region src/core/persistence/persistence.d.ts
|
|
852
|
-
/**
|
|
853
|
-
* Serializes the current upload state into a JSON-safe structure.
|
|
854
|
-
* Only serializes items that have a valid 'intent', as these are the only ones
|
|
855
|
-
* that can be resumed cleanly.
|
|
856
|
-
*/
|
|
857
|
-
declare function serializeSnapshot<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase>(state: UploadState<M, C, P, R>, version: number): PersistedSnapshot<M, C, P>;
|
|
858
|
-
/**
|
|
859
|
-
* Deserializes a persisted snapshot back into a store state.
|
|
860
|
-
*
|
|
861
|
-
* Important:
|
|
862
|
-
* - Browser `File` objects cannot be restored from persistence.
|
|
863
|
-
* - We restore resumable items (those with a cursor) into the `paused` phase,
|
|
864
|
-
* with `file` left undefined. Your UI can ask the user to rebind the file.
|
|
865
|
-
*/
|
|
866
|
-
declare function deserializeSnapshot<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase>(raw: unknown, opts: {
|
|
867
|
-
isPurpose?: (value: string) => value is P;
|
|
868
|
-
isIntent?: (value: unknown) => value is M[keyof M];
|
|
869
|
-
hasStrategy: (value: string) => boolean;
|
|
870
|
-
}): UploadState<M, C, P, R> | null;
|
|
871
|
-
//#endregion
|
|
872
|
-
//#region src/core/utils/emitter/emitter.types.d.ts
|
|
873
|
-
/**
|
|
874
|
-
* Minimal typed event emitter interface.
|
|
875
|
-
*
|
|
876
|
-
* Use this to expose strongly-typed events from your store.
|
|
877
|
-
*
|
|
878
|
-
* @typeParam E - Event map (`eventName -> payload`).
|
|
879
|
-
*/
|
|
880
|
-
type TypedEmitter<E extends Record<string, unknown>> = {
|
|
881
|
-
/**
|
|
882
|
-
* Subscribe to an event.
|
|
883
|
-
* @returns Unsubscribe function.
|
|
884
|
-
*/
|
|
885
|
-
on<K$1 extends keyof E & string>(type: K$1, cb: (payload: E[K$1]) => void): () => void;
|
|
886
|
-
/**
|
|
887
|
-
* Unsubscribe from an event.
|
|
888
|
-
* @returns Unsubscribe function.
|
|
889
|
-
*/
|
|
890
|
-
off<K$1 extends keyof E & string>(type: K$1, cb: (payload: E[K$1]) => void): () => void;
|
|
891
|
-
/** Emit an event to all listeners. */
|
|
892
|
-
emit<K$1 extends keyof E & string>(type: K$1, payload: E[K$1]): void;
|
|
893
|
-
};
|
|
894
|
-
//#endregion
|
|
895
|
-
//#region src/core/utils/emitter/index.d.ts
|
|
896
|
-
declare function createTypedEmitter<E extends Record<string, unknown>>(): TypedEmitter<E>;
|
|
897
|
-
//#endregion
|
|
898
|
-
//#region src/core/engine/event-map.types.d.ts
|
|
899
|
-
/**
|
|
900
|
-
* Public event map emitted to consumers.
|
|
901
|
-
*
|
|
902
|
-
* Consumers subscribe via {@link TypedEmitter.on}.
|
|
903
|
-
*/
|
|
904
|
-
type UploadEventMap<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase = UploadResultBase> = {
|
|
905
|
-
'file.added': {
|
|
906
|
-
localId: string;
|
|
907
|
-
purpose: P;
|
|
908
|
-
file: File;
|
|
909
|
-
fingerprint: FileFingerprint;
|
|
910
|
-
};
|
|
911
|
-
'file.rejected': {
|
|
912
|
-
file: File;
|
|
913
|
-
reason: RejectReason;
|
|
914
|
-
};
|
|
915
|
-
'validation.ok': {
|
|
916
|
-
localId: string;
|
|
917
|
-
};
|
|
918
|
-
'validation.failed': {
|
|
919
|
-
localId: string;
|
|
920
|
-
reason: RejectReason;
|
|
921
|
-
};
|
|
922
|
-
'intent.creating': {
|
|
923
|
-
localId: string;
|
|
924
|
-
};
|
|
925
|
-
'intent.created': {
|
|
926
|
-
localId: string;
|
|
927
|
-
intent: M[keyof M];
|
|
928
|
-
};
|
|
929
|
-
'intent.failed': {
|
|
930
|
-
localId: string;
|
|
931
|
-
error: UploadError;
|
|
932
|
-
retryable: boolean;
|
|
933
|
-
};
|
|
934
|
-
'upload.queued': {
|
|
935
|
-
localId: string;
|
|
936
|
-
};
|
|
937
|
-
'upload.resumed': {
|
|
938
|
-
localId: string;
|
|
939
|
-
};
|
|
940
|
-
'upload.started': {
|
|
941
|
-
localId: string;
|
|
942
|
-
};
|
|
943
|
-
'upload.progress': {
|
|
944
|
-
localId: string;
|
|
945
|
-
pct: number;
|
|
946
|
-
uploadedBytes: number;
|
|
947
|
-
totalBytes: number;
|
|
948
|
-
};
|
|
949
|
-
'upload.cursor': {
|
|
950
|
-
localId: string;
|
|
951
|
-
cursor: AnyCursor<C>;
|
|
952
|
-
};
|
|
953
|
-
'upload.paused': {
|
|
954
|
-
localId: string;
|
|
955
|
-
cursor: AnyCursor<C>;
|
|
956
|
-
};
|
|
957
|
-
'upload.canceled': {
|
|
958
|
-
localId: string;
|
|
959
|
-
};
|
|
960
|
-
'upload.completing': {
|
|
961
|
-
localId: string;
|
|
962
|
-
};
|
|
963
|
-
'upload.completed': {
|
|
964
|
-
localId: string;
|
|
965
|
-
result: R;
|
|
966
|
-
completedBy: UploadCompletionKind;
|
|
967
|
-
};
|
|
968
|
-
'upload.error': {
|
|
969
|
-
localId: string;
|
|
970
|
-
error: UploadError;
|
|
971
|
-
retryable: boolean;
|
|
972
|
-
};
|
|
973
|
-
};
|
|
974
|
-
//#endregion
|
|
975
|
-
//#region src/core/engine/store/store.types.d.ts
|
|
976
|
-
/**
|
|
977
|
-
* Upload store interface used by UI adapters and application code.
|
|
978
|
-
*
|
|
979
|
-
* The store is intentionally minimal:
|
|
980
|
-
* - state is read through {@link UploadStore.getSnapshot}
|
|
981
|
-
* - updates are observed through {@link UploadStore.subscribe} and {@link UploadStore.on}
|
|
982
|
-
* - actions are performed through {@link UploadStore.dispatch}
|
|
983
|
-
*
|
|
984
|
-
* @template M - Intent map type (keyed by strategy id)
|
|
985
|
-
* @template C - Cursor map type (keyed by strategy id)
|
|
986
|
-
* @template P - Purpose string union type
|
|
987
|
-
*/
|
|
988
|
-
interface UploadStore<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase = UploadResultBase> {
|
|
989
|
-
/**
|
|
990
|
-
* Returns the current immutable state snapshot.
|
|
991
|
-
* Useful for React loops or debugging.
|
|
992
|
-
*/
|
|
993
|
-
getSnapshot(): UploadState<M, C, P, R>;
|
|
994
|
-
/**
|
|
995
|
-
* Subscribes to ANY state change.
|
|
996
|
-
* The listener is called after the reducer has run and effects have been scheduled.
|
|
997
|
-
* @param listener - Listener function to call on state change
|
|
998
|
-
*/
|
|
999
|
-
subscribe(listener: () => void): () => void;
|
|
1000
|
-
/**
|
|
1001
|
-
* Main entry point for user actions.
|
|
1002
|
-
* Converts external commands into internal state transitions and side effects.
|
|
1003
|
-
*
|
|
1004
|
-
* @param cmd The command to execute (e.g. 'addFiles', 'start', 'pause')
|
|
1005
|
-
*/
|
|
1006
|
-
dispatch(cmd: UploadCommand<P>): void;
|
|
1007
|
-
/**
|
|
1008
|
-
* Subscribes to specific events (like 'file.added', 'upload.progress').
|
|
1009
|
-
* Wraps the internal typed emitter.
|
|
1010
|
-
*/
|
|
1011
|
-
on: <K$1 extends keyof UploadEventMap<M, C, P, R> & string>(type: K$1, cb: (payload: UploadEventMap<M, C, P, R>[K$1]) => void) => () => void;
|
|
1012
|
-
/**
|
|
1013
|
-
* Unsubscribes from specific events (like 'file.added', 'upload.progress').
|
|
1014
|
-
* Wraps the internal typed emitter.
|
|
1015
|
-
*/
|
|
1016
|
-
off: <K$1 extends keyof UploadEventMap<M, C, P, R> & string>(type: K$1, cb: (payload: UploadEventMap<M, C, P, R>[K$1]) => void) => () => void;
|
|
1017
|
-
/**
|
|
1018
|
-
* Waits for the given localIds to reach a terminal state.
|
|
1019
|
-
*/
|
|
1020
|
-
waitFor(localIds: string[]): Promise<Array<UploadOutcome<R>>>;
|
|
1021
|
-
}
|
|
1022
|
-
/**
|
|
1023
|
-
* Options used to construct a store runtime.
|
|
1024
|
-
*
|
|
1025
|
-
* In practice you provide:
|
|
1026
|
-
* - a backend adapter ({@link UploadApi}) that creates intents and finalizes uploads
|
|
1027
|
-
* - a transport implementation (XHR, fetch, etc.) used by strategies
|
|
1028
|
-
* - a strategy registry describing what upload strategies exist and how to run them
|
|
1029
|
-
* - configuration rules for validation, concurrency, retries, and progress throttling
|
|
1030
|
-
*
|
|
1031
|
-
* Hooks and plugins are optional and let you observe or extend behavior without forking
|
|
1032
|
-
* the engine.
|
|
1033
|
-
*
|
|
1034
|
-
* @template M - Intent map type (keyed by strategy id)
|
|
1035
|
-
* @template C - Cursor map type (keyed by strategy id)
|
|
1036
|
-
* @template P - Purpose string union type
|
|
1037
|
-
*/
|
|
1038
|
-
interface StoreOptions<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase = UploadResultBase> {
|
|
1039
|
-
/** Initial state to hydrate from (e.g. from localStorage) */
|
|
1040
|
-
initialState?: UploadState<M, C, P, R>;
|
|
1041
|
-
/** Static configuration rules (defaults are applied). */
|
|
1042
|
-
config?: UploadConfigInput<P>;
|
|
1043
|
-
/** Persistence adapter and options */
|
|
1044
|
-
persistence?: PersistenceOptions<M, C, P, R>;
|
|
1045
|
-
/** Backend API adapter for creating intents and finalizing uploads */
|
|
1046
|
-
api: UploadApi<M, P, R>;
|
|
1047
|
-
/** Network transport (XHR/Fetch) for the actual file data transfer */
|
|
1048
|
-
transport?: UploadTransport;
|
|
1049
|
-
/** Registry of available upload strategies (multipart, simple, etc.) */
|
|
1050
|
-
strategies: StrategyRegistry<M, C, P, R>;
|
|
1051
|
-
/** Optional plugins to extend functionality (e.g. debugging, metrics) */
|
|
1052
|
-
plugins?: Array<UploadPlugin<M, C, P, R>>;
|
|
1053
|
-
/** Lifecycle hooks for observing internal events */
|
|
1054
|
-
hooks?: UploadHooks<M, C, P, R>;
|
|
1055
|
-
/**
|
|
1056
|
-
* Optional custom fingerprinting (e.g. include sha256).
|
|
1057
|
-
* Must be synchronous to keep addFiles fast.
|
|
1058
|
-
*/
|
|
1059
|
-
fingerprint?: (file: File) => FileFingerprint;
|
|
1060
|
-
/**
|
|
1061
|
-
* If returns non-null, it rejects the file.
|
|
1062
|
-
* Runs after built-in config validation.
|
|
1063
|
-
*/
|
|
1064
|
-
validateFile?: (file: File, purpose: P) => RejectReason | null;
|
|
1065
|
-
/**
|
|
1066
|
-
* Optional custom error normalizer.
|
|
1067
|
-
* Convert raw errors (from fetch, XHR, etc.) into your custom UploadError shape.
|
|
1068
|
-
*/
|
|
1069
|
-
errorNormalizer?: (err: unknown) => UploadError;
|
|
1070
|
-
}
|
|
1071
|
-
/**
|
|
1072
|
-
* Persistence options.
|
|
1073
|
-
*
|
|
1074
|
-
* Used to configure the upload store persistence layer.
|
|
1075
|
-
*/
|
|
1076
|
-
type DeserializeContext<M extends IntentMap, C extends CursorMap<M>, P extends string> = {
|
|
1077
|
-
isPurpose?: (value: string) => value is P;
|
|
1078
|
-
isIntent?: (value: unknown) => value is M[keyof M];
|
|
1079
|
-
hasStrategy: (value: string) => boolean;
|
|
1080
|
-
};
|
|
1081
|
-
type PersistenceOptions<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase> = {
|
|
1082
|
-
/** Persistence key (e.g. localStorage key) */
|
|
1083
|
-
key: string;
|
|
1084
|
-
/** Persistence schema version (not app version) */
|
|
1085
|
-
version: number;
|
|
1086
|
-
/** Debounce delay in milliseconds (default: 200) */
|
|
1087
|
-
debounceMs?: number;
|
|
1088
|
-
/** Persistence adapter */
|
|
1089
|
-
adapter: PersistenceAdapter;
|
|
1090
|
-
/**
|
|
1091
|
-
* Optional custom snapshot serializer.
|
|
1092
|
-
* Convert the upload state into a JSON-safe snapshot.
|
|
1093
|
-
*/
|
|
1094
|
-
serialize?: (state: UploadState<M, C, P, R>, version: number) => PersistedSnapshot<M, C, P>;
|
|
1095
|
-
/**
|
|
1096
|
-
* Optional custom snapshot deserializer.
|
|
1097
|
-
* Convert a JSON-safe snapshot into the upload state.
|
|
1098
|
-
*/
|
|
1099
|
-
deserialize?: (raw: unknown, ctx: DeserializeContext<M, C, P>) => UploadState<M, C, P, R> | null;
|
|
1100
|
-
/**
|
|
1101
|
-
* Runtime guard for purpose strings when using the default deserializer.
|
|
1102
|
-
*/
|
|
1103
|
-
isPurpose?: (value: string) => value is P;
|
|
1104
|
-
/**
|
|
1105
|
-
* Runtime guard for intent objects when using the default deserializer.
|
|
1106
|
-
*/
|
|
1107
|
-
isIntent?: (value: unknown) => value is M[keyof M];
|
|
1108
|
-
};
|
|
1109
|
-
/**
|
|
1110
|
-
* Internal record describing a currently running upload request.
|
|
1111
|
-
*
|
|
1112
|
-
* The store keeps one inflight entry per `localId` while the strategy's `start()` is running.
|
|
1113
|
-
* The {@link AbortController} is used to pause/cancel, while `mode` tracks which user intent
|
|
1114
|
-
* caused the abort so the handler can map it back into a correct state transition.
|
|
1115
|
-
*/
|
|
1116
|
-
type InflightUpload = {
|
|
1117
|
-
controller: AbortController;
|
|
1118
|
-
mode: 'normal' | 'pause' | 'cancel';
|
|
1119
|
-
started: boolean;
|
|
1120
|
-
};
|
|
1121
|
-
/**
|
|
1122
|
-
* Internal runtime container shared across dispatch, scheduler, and handlers.
|
|
1123
|
-
*
|
|
1124
|
-
* @template M - Intent map type
|
|
1125
|
-
* @template C - Cursor map type
|
|
1126
|
-
* @template P - Purpose string union type
|
|
1127
|
-
*/
|
|
1128
|
-
type StoreRuntime<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase = UploadResultBase> = {
|
|
1129
|
-
/** Store options */
|
|
1130
|
-
opts: StoreOptions<M, C, P, R> & {
|
|
1131
|
-
config: UploadConfig<P>;
|
|
1132
|
-
transport: UploadTransport;
|
|
1133
|
-
};
|
|
1134
|
-
/** Current state */
|
|
1135
|
-
state: UploadState<M, C, P, R>;
|
|
1136
|
-
/** Listeners for external events */
|
|
1137
|
-
listeners: Set<() => void>;
|
|
1138
|
-
/** Typed event emitter */
|
|
1139
|
-
emitter: TypedEmitter<UploadEventMap<M, C, P, R>>;
|
|
1140
|
-
/** Reducer */
|
|
1141
|
-
reduce: ReturnType<typeof createReducer<M, C, P, R>>;
|
|
1142
|
-
/** In-flight uploads */
|
|
1143
|
-
inflightUploads: Map<string, InflightUpload>;
|
|
1144
|
-
/** In-flight intents */
|
|
1145
|
-
inflightIntents: Map<string, AbortController>;
|
|
1146
|
-
/** In-flight completes */
|
|
1147
|
-
inflightCompletes: Map<string, AbortController>;
|
|
1148
|
-
/** Effect queue */
|
|
1149
|
-
effectQueue: Array<() => Promise<void>>;
|
|
1150
|
-
/** Effect queue processing */
|
|
1151
|
-
processingEffects: boolean;
|
|
1152
|
-
/** Effect queue scheduling */
|
|
1153
|
-
scheduling: boolean;
|
|
1154
|
-
/** Notifies listeners */
|
|
1155
|
-
notify: () => void;
|
|
1156
|
-
/** Schedules work */
|
|
1157
|
-
scheduleWork: () => void;
|
|
1158
|
-
/** Applies an internal event */
|
|
1159
|
-
applyInternal: (event: InternalEvent<M, C, P, R>) => void;
|
|
1160
|
-
/** Applies a command */
|
|
1161
|
-
applyCommand: (cmd: UploadCommand<P>) => void;
|
|
1162
|
-
/** Enqueues an effect */
|
|
1163
|
-
enqueueEffect: (effect: () => Promise<void>) => void;
|
|
1164
|
-
/** Processes effects */
|
|
1165
|
-
processEffects: () => Promise<void>;
|
|
1166
|
-
/** Set by createUploadStore after construction; used by handlers for retries etc. */
|
|
1167
|
-
dispatch: (cmd: UploadCommand<P>) => void;
|
|
1168
|
-
};
|
|
1169
|
-
//#endregion
|
|
1170
|
-
//#region src/core/engine/store/index.d.ts
|
|
1171
|
-
/**
|
|
1172
|
-
* Creates an upload store instance.
|
|
1173
|
-
*
|
|
1174
|
-
* This is the main runtime object you interact with from the outside:
|
|
1175
|
-
* - dispatch user commands (add files, start, pause, cancel, resume)
|
|
1176
|
-
* - subscribe to state changes (for UI rendering)
|
|
1177
|
-
* - subscribe to typed events (for progress, errors, and lifecycle)
|
|
1178
|
-
*
|
|
1179
|
-
* Plugins are initialized once during construction and receive a minimal store
|
|
1180
|
-
* proxy (events, dispatch, snapshot access) to avoid tight coupling.
|
|
1181
|
-
*
|
|
1182
|
-
* @template M - Intent map type (keyed by strategy id)
|
|
1183
|
-
* @template C - Cursor map type (keyed by strategy id)
|
|
1184
|
-
* @template P - Purpose string union type
|
|
1185
|
-
*
|
|
1186
|
-
* @param opts - Store options (config, backend API, strategies, transport, hooks)
|
|
1187
|
-
* @returns A configured {@link UploadStore} instance.
|
|
1188
|
-
*/
|
|
1189
|
-
declare function createUploadStore<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase = UploadResultBase>(opts: StoreOptions<M, C, P, R>): UploadStore<M, C, P, R>;
|
|
1190
|
-
//#endregion
|
|
1191
|
-
//#region src/core/client/plugins.types.d.ts
|
|
1192
|
-
/**
|
|
1193
|
-
* Optional hooks for observing internal behavior.
|
|
1194
|
-
*
|
|
1195
|
-
* Use these for diagnostics, analytics, logging, or devtools.
|
|
1196
|
-
*/
|
|
1197
|
-
type UploadHooks<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase = UploadResultBase> = {
|
|
1198
|
-
/**
|
|
1199
|
-
* Called after internal events are processed (depending on your runtime wiring).
|
|
1200
|
-
* Prefer this over subscribing to public events if you need full fidelity.
|
|
1201
|
-
*/
|
|
1202
|
-
onInternalEvent?: (event: InternalEvent<M, C, P, R>, state: UploadState<M, C, P, R>) => void;
|
|
1203
|
-
};
|
|
1204
|
-
/**
|
|
1205
|
-
* Store plugins.
|
|
1206
|
-
*
|
|
1207
|
-
* Plugins can subscribe to store events and dispatch commands.
|
|
1208
|
-
* They should not reach into internal state mutably.
|
|
1209
|
-
*/
|
|
1210
|
-
type UploadPlugin<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase = UploadResultBase> = {
|
|
1211
|
-
/** Plugin name (for debugging). */
|
|
1212
|
-
name: string;
|
|
1213
|
-
/**
|
|
1214
|
-
* Setup callback called once when the store is created.
|
|
1215
|
-
* The plugin can register event listeners and drive behavior.
|
|
1216
|
-
*/
|
|
1217
|
-
setup: (ctx: Pick<UploadStore<M, C, P, R>, 'on' | 'dispatch' | 'getSnapshot'>) => void;
|
|
1218
|
-
};
|
|
1219
|
-
//#endregion
|
|
1220
|
-
//#region src/core/client/uploadClient.d.ts
|
|
1221
|
-
type UploadClient<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase = UploadResultBase> = UploadStore<M, C, P, R>;
|
|
1222
|
-
declare function createUploadClient<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase = UploadResultBase>(opts: StoreOptions<M, C, P, R>): UploadClient<M, C, P, R>;
|
|
1223
|
-
//#endregion
|
|
1224
|
-
//#region src/core/engine/validation/file.d.ts
|
|
1225
|
-
declare function validateFile<P extends string>(file: File, purpose: P, config: UploadConfig<P>): RejectReason | null;
|
|
1226
|
-
//#endregion
|
|
1227
|
-
//#region src/core/engine/validation/intent.d.ts
|
|
1228
|
-
declare function validateIntent(intent: unknown, strategy: string): Error | null;
|
|
1229
|
-
//#endregion
|
|
1230
|
-
//#region src/core/engine/validation/list.d.ts
|
|
1231
|
-
declare function validateFileList<P extends string>(files: File[], purpose: P, config: UploadConfig<P>, existingCount?: number): {
|
|
1232
|
-
valid: File[];
|
|
1233
|
-
rejected: Array<{
|
|
1234
|
-
file: File;
|
|
1235
|
-
reason: RejectReason;
|
|
1236
|
-
}>;
|
|
1237
|
-
};
|
|
1238
|
-
//#endregion
|
|
1239
|
-
//#region src/core/utils/async.d.ts
|
|
1240
|
-
declare function sleep(ms: number): Promise<void>;
|
|
1241
|
-
//#endregion
|
|
1242
|
-
//#region src/core/utils/constants.d.ts
|
|
1243
|
-
/**
|
|
1244
|
-
* Default retry delay base in milliseconds.
|
|
1245
|
-
* Used for exponential backoff calculation: base * 2^(attempt - 1)
|
|
1246
|
-
*/
|
|
1247
|
-
declare const DEFAULT_RETRY_DELAY_BASE_MS = 500;
|
|
1248
|
-
/**
|
|
1249
|
-
* Maximum retry delay in milliseconds.
|
|
1250
|
-
* Caps exponential backoff to prevent excessive delays.
|
|
1251
|
-
*/
|
|
1252
|
-
declare const DEFAULT_RETRY_DELAY_MAX_MS = 10000;
|
|
1253
|
-
/**
|
|
1254
|
-
* Default progress event throttle in milliseconds.
|
|
1255
|
-
* Prevents excessive progress updates from overwhelming the UI.
|
|
1256
|
-
*/
|
|
1257
|
-
declare const DEFAULT_PROGRESS_THROTTLE_MS = 100;
|
|
1258
|
-
/**
|
|
1259
|
-
* Default maximum number of retry attempts.
|
|
1260
|
-
*/
|
|
1261
|
-
declare const DEFAULT_MAX_ATTEMPTS = 3;
|
|
1262
|
-
/**
|
|
1263
|
-
* Default maximum number of concurrent uploads.
|
|
1264
|
-
*/
|
|
1265
|
-
declare const DEFAULT_MAX_CONCURRENT_UPLOADS = 3;
|
|
1266
|
-
/**
|
|
1267
|
-
* Default maximum number of items to keep in memory.
|
|
1268
|
-
*/
|
|
1269
|
-
declare const DEFAULT_MAX_ITEMS = 100;
|
|
1270
|
-
//#endregion
|
|
1271
|
-
//#region src/core/utils/fingerprint.d.ts
|
|
1272
|
-
/**
|
|
1273
|
-
* Builds a lightweight fingerprint from a {@link File}.
|
|
1274
|
-
*/
|
|
1275
|
-
declare function computeFingerprint(file: File): FileFingerprint;
|
|
1276
|
-
/**
|
|
1277
|
-
* Compares two file fingerprints.
|
|
1278
|
-
*/
|
|
1279
|
-
declare function fingerprintMatches(a: FileFingerprint, b: FileFingerprint): boolean;
|
|
1280
|
-
//#endregion
|
|
1281
|
-
//#region src/core/utils/guards.d.ts
|
|
1282
|
-
declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
1283
|
-
//#endregion
|
|
1284
|
-
//#region src/core/utils/id.d.ts
|
|
1285
|
-
declare function generateId(): string;
|
|
1286
|
-
//#endregion
|
|
1287
|
-
//#region src/react/upload-provider.d.ts
|
|
1288
|
-
/**
|
|
1289
|
-
* Provider component that makes the upload store available to child components.
|
|
1290
|
-
*
|
|
1291
|
-
* @template M - Intent map type
|
|
1292
|
-
* @template C - Cursor map type
|
|
1293
|
-
* @template P - Purpose type
|
|
1294
|
-
*
|
|
1295
|
-
* @param props - Provider props
|
|
1296
|
-
* @param props.store - Upload store instance to provide
|
|
1297
|
-
* @param props.children - Child components that can access the store
|
|
1298
|
-
*
|
|
1299
|
-
* @returns {JSX.Element} Context provider wrapping children
|
|
1300
|
-
*
|
|
1301
|
-
* @example
|
|
1302
|
-
* ```tsx
|
|
1303
|
-
* <UploadProvider store={store}>
|
|
1304
|
-
* <UploadDropzone purpose="avatar" />
|
|
1305
|
-
* </UploadProvider>
|
|
1306
|
-
* ```
|
|
1307
|
-
*/
|
|
1308
|
-
declare function UploadProvider<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase = UploadResultBase>({
|
|
1309
|
-
store,
|
|
1310
|
-
children
|
|
1311
|
-
}: {
|
|
1312
|
-
store: UploadStore<M, C, P, R>;
|
|
1313
|
-
children: ReactNode;
|
|
1314
|
-
}): React.JSX.Element;
|
|
1315
|
-
/**
|
|
1316
|
-
* Hook to access the upload store from React context.
|
|
1317
|
-
*
|
|
1318
|
-
* @template M - Intent map type
|
|
1319
|
-
* @template C - Cursor map type
|
|
1320
|
-
* @template P - Purpose type
|
|
1321
|
-
*
|
|
1322
|
-
* @returns {UploadStore<M, C, P>} The upload store instance
|
|
1323
|
-
* @throws {Error} If called outside of UploadProvider
|
|
1324
|
-
*
|
|
1325
|
-
* @example
|
|
1326
|
-
* ```tsx
|
|
1327
|
-
* const store = useUploadStore()
|
|
1328
|
-
* const snapshot = store.getSnapshot()
|
|
1329
|
-
* ```
|
|
1330
|
-
*/
|
|
1331
|
-
declare function useUploadStore<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase = UploadResultBase>(): UploadStore<M, C, P, R>;
|
|
1332
|
-
//#endregion
|
|
1333
|
-
//#region src/react/use-uploader.d.ts
|
|
1334
|
-
declare function createUploadFactory<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase = UploadResultBase>(store: UploadStore<M, C, P, R>): () => Uploader<M, C, P, R>;
|
|
1335
|
-
type PickItemsByPhase<Phase extends UploadPhase> = Extract<UploadItem<IntentMap, CursorMap<IntentMap>, string, UploadResultBase>, {
|
|
1336
|
-
phase: Phase;
|
|
1337
|
-
}>;
|
|
1338
|
-
type Uploader<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase> = {
|
|
1339
|
-
items: UploadItem<M, C, P, R>[];
|
|
1340
|
-
byPhase: Record<string, UploadItem<M, C, P, R>[]>;
|
|
1341
|
-
dispatch: (cmd: UploadCommand<P>) => void;
|
|
1342
|
-
on: <K$1 extends keyof UploadEventMap<M, C, P, R> & string>(type: K$1, cb: (payload: UploadEventMap<M, C, P, R>[K$1]) => void) => () => void;
|
|
1343
|
-
off: <K$1 extends keyof UploadEventMap<M, C, P, R> & string>(type: K$1, cb: (payload: UploadEventMap<M, C, P, R>[K$1]) => void) => () => void;
|
|
1344
|
-
uploading: UploadItem<M, C, P, R>[];
|
|
1345
|
-
paused: UploadItem<M, C, P, R>[];
|
|
1346
|
-
completed: UploadItem<M, C, P, R>[];
|
|
1347
|
-
failed: UploadItem<M, C, P, R>[];
|
|
1348
|
-
ready: UploadItem<M, C, P, R>[];
|
|
1349
|
-
};
|
|
1350
|
-
declare function useUploader<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase = UploadResultBase>(): Uploader<M, C, P, R>;
|
|
1351
|
-
declare function useUploader<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase = UploadResultBase>(store: UploadStore<M, C, P, R>): Uploader<M, C, P, R>;
|
|
1352
|
-
declare function useUploaderActions<M extends IntentMap, C extends CursorMap<M>, P extends string, R extends UploadResultBase = UploadResultBase>(): {
|
|
1353
|
-
dispatch: (cmd: UploadCommand<P>) => void;
|
|
1354
|
-
on: <K$1 extends keyof UploadEventMap<M_1, C_1, P_1, R_1> & string>(type: K$1, cb: (payload: UploadEventMap<M, C, P, R>[K$1]) => void) => () => void;
|
|
1355
|
-
store: UploadStore<M, C, P, R>;
|
|
1356
|
-
};
|
|
1357
|
-
//#endregion
|
|
1358
|
-
//#region src/strategies/multipart/index.d.ts
|
|
1359
|
-
type MultipartIntent = {
|
|
1360
|
-
strategy: 'multipart';
|
|
1361
|
-
fileId: string;
|
|
1362
|
-
uploadId: string;
|
|
1363
|
-
partSize: number;
|
|
1364
|
-
partCount: number;
|
|
1365
|
-
parts?: Array<{
|
|
1366
|
-
partNumber: number;
|
|
1367
|
-
url: string;
|
|
1368
|
-
headers?: Record<string, string>;
|
|
1369
|
-
}>;
|
|
1370
|
-
};
|
|
1371
|
-
type MultipartCursor = {
|
|
1372
|
-
done: Array<{
|
|
1373
|
-
partNumber: number;
|
|
1374
|
-
etag: string;
|
|
1375
|
-
size: number;
|
|
1376
|
-
}>;
|
|
1377
|
-
/**
|
|
1378
|
-
* Marks that the multipart session was completed on the backend (parts assembled).
|
|
1379
|
-
* This prevents re-sending completeMultipart on resume.
|
|
1380
|
-
*/
|
|
1381
|
-
completed?: true;
|
|
1382
|
-
};
|
|
1383
|
-
declare function multipartStrategy<M extends IntentMap & {
|
|
1384
|
-
multipart: MultipartIntent;
|
|
1385
|
-
}, C extends CursorMap<M> & {
|
|
1386
|
-
multipart?: MultipartCursor;
|
|
1387
|
-
}, P extends string = string, R extends UploadResultBase = UploadResultBase>(opts?: {
|
|
1388
|
-
maxPartConcurrency?: number;
|
|
1389
|
-
}): UploadStrategy<M, C, P, R, 'multipart'>;
|
|
1390
|
-
//#endregion
|
|
1391
|
-
//#region src/strategies/post/index.d.ts
|
|
1392
|
-
type PostIntent = {
|
|
1393
|
-
/** Strategy identifier - must be 'post' */
|
|
1394
|
-
strategy: 'post';
|
|
1395
|
-
/** Backend file identifier */
|
|
1396
|
-
fileId: string;
|
|
1397
|
-
/** Presigned POST URL (form action) */
|
|
1398
|
-
url: string;
|
|
1399
|
-
/** Form fields to include before the file */
|
|
1400
|
-
fields: Record<string, string>;
|
|
1401
|
-
/** Optional expiration timestamp for the presigned URL */
|
|
1402
|
-
expiresAt?: string;
|
|
1403
|
-
};
|
|
1404
|
-
type PostCursor = {
|
|
1405
|
-
/** Bytes uploaded (for progress display only) */
|
|
1406
|
-
uploadedBytes: number;
|
|
1407
|
-
};
|
|
1408
|
-
declare function PostStrategy<M extends IntentMap & {
|
|
1409
|
-
post: PostIntent;
|
|
1410
|
-
}, C extends CursorMap<M> & {
|
|
1411
|
-
post?: PostCursor;
|
|
1412
|
-
}, P extends string = string, R extends UploadResultBase = UploadResultBase>(): UploadStrategy<M, C, P, R, 'post'>;
|
|
1413
|
-
//#endregion
|
|
1414
|
-
//#region src/strategies/registry/index.d.ts
|
|
1415
|
-
declare function createStrategyRegistry<M extends IntentMap, C extends CursorMap<M>, P extends string = string, R extends UploadResultBase = UploadResultBase>(): StrategyRegistry<M, C, P, R>;
|
|
1416
|
-
//#endregion
|
|
1417
|
-
export { AnyCursor, AnyIntent, BuiltInUploadError, CursorMap, DEFAULT_MAX_ATTEMPTS, DEFAULT_MAX_CONCURRENT_UPLOADS, DEFAULT_MAX_ITEMS, DEFAULT_PROGRESS_THROTTLE_MS, DEFAULT_RETRY_DELAY_BASE_MS, DEFAULT_RETRY_DELAY_MAX_MS, DeserializeContext, FileFingerprint, IndexedDBAdapter, InflightUpload, IntentBase, IntentMap, InternalEvent, LocalStorageAdapter, MemoryAdapter, MultipartCursor, MultipartIntent, PersistedSnapshot, PersistedUploadItem, PersistenceAdapter, PersistenceOptions, PickItemsByPhase, PostCursor, PostIntent, PostStrategy, RejectReason, RetryDecision, StoreOptions, StoreRuntime, type StrategyCtx, StrategyKey, type StrategyRegistry, type TypedEmitter, UploadApi, UploadClient, UploadCommand, UploadCompletionKind, UploadConfig, UploadConfigInput, UploadError, UploadErrorBase, UploadEventMap, UploadHooks, UploadItem, UploadOutcome, UploadPhase, UploadPlugin, UploadProgress, UploadProvider, UploadResultBase, UploadState, UploadStore, type UploadStrategy, UploadTransport, UploadValidationRules, WithSignal, computeFingerprint, createReducer, createStrategyRegistry, createTypedEmitter, createUploadClient, createUploadFactory, createUploadStore, createXHRTransport, deserializeSnapshot, fingerprintMatches, generateId, isRecord, multipartStrategy, resolveUploadConfig, serializeSnapshot, sleep, useUploadStore, useUploader, useUploaderActions, validateFile, validateFileList, validateIntent };
|
|
1
|
+
import { a as AnyCursor, c as WithSignal, d as IntentBase, f as IntentMap, i as UploadTransport, l as UploadResultBase, n as StrategyRegistry, o as CursorMap, p as StrategyKey, r as UploadStrategy, s as UploadApi, t as StrategyCtx, u as AnyIntent } from "./strategy.types-gg9ZStRe.js";
|
|
2
|
+
import { $ as RejectReason, A as serializeSnapshot, B as UploadItem, C as StoreOptions, D as createTypedEmitter, E as UploadEventMap, F as PersistedUploadItem, G as UploadCommand, H as UploadProgress, I as PersistenceAdapter, J as resolveUploadConfig, K as UploadConfig, L as UploadState, M as LocalStorageAdapter, N as IndexedDBAdapter, O as TypedEmitter, P as PersistedSnapshot, Q as BuiltInUploadError, R as createReducer, S as PersistenceOptions, T as UploadStore, U as UploadCompletionKind, V as UploadPhase, W as UploadOutcome, X as createXHRTransport, Y as RetryDecision, Z as FileFingerprint, _ as UploadHooks, a as DEFAULT_MAX_ATTEMPTS, b as DeserializeContext, c as DEFAULT_PROGRESS_THROTTLE_MS, d as sleep, et as UploadError, f as validateFileList, g as createUploadClient, h as UploadClient, i as fingerprintMatches, j as MemoryAdapter, k as deserializeSnapshot, l as DEFAULT_RETRY_DELAY_BASE_MS, m as validateFile, n as isRecord, nt as UploadValidationRules, o as DEFAULT_MAX_CONCURRENT_UPLOADS, p as validateIntent, q as UploadConfigInput, r as computeFingerprint, s as DEFAULT_MAX_ITEMS, t as generateId, tt as UploadErrorBase, u as DEFAULT_RETRY_DELAY_MAX_MS, v as UploadPlugin, w as StoreRuntime, x as InflightUpload, y as createUploadStore, z as InternalEvent } from "./index-BXg9WIce.js";
|
|
3
|
+
import { PickItemsByPhase, UploadProvider, UploaderActions, createUploadFactory, useOptionalUploadStore, useUploadStore, useUploader, useUploaderActions } from "./react/index.js";
|
|
4
|
+
import { MultipartCursor, MultipartIntent, PostCursor, PostIntent, PostStrategy, createStrategyRegistry, multipartStrategy } from "./strategies/index.js";
|
|
5
|
+
export { AnyCursor, AnyIntent, BuiltInUploadError, CursorMap, DEFAULT_MAX_ATTEMPTS, DEFAULT_MAX_CONCURRENT_UPLOADS, DEFAULT_MAX_ITEMS, DEFAULT_PROGRESS_THROTTLE_MS, DEFAULT_RETRY_DELAY_BASE_MS, DEFAULT_RETRY_DELAY_MAX_MS, DeserializeContext, FileFingerprint, IndexedDBAdapter, InflightUpload, IntentBase, IntentMap, InternalEvent, LocalStorageAdapter, MemoryAdapter, MultipartCursor, MultipartIntent, PersistedSnapshot, PersistedUploadItem, PersistenceAdapter, PersistenceOptions, PickItemsByPhase, PostCursor, PostIntent, PostStrategy, RejectReason, RetryDecision, StoreOptions, StoreRuntime, StrategyCtx, StrategyKey, StrategyRegistry, TypedEmitter, UploadApi, UploadClient, UploadCommand, UploadCompletionKind, UploadConfig, UploadConfigInput, UploadError, UploadErrorBase, UploadEventMap, UploadHooks, UploadItem, UploadOutcome, UploadPhase, UploadPlugin, UploadProgress, UploadProvider, UploadResultBase, UploadState, UploadStore, UploadStrategy, UploadTransport, UploadValidationRules, UploaderActions, WithSignal, computeFingerprint, createReducer, createStrategyRegistry, createTypedEmitter, createUploadClient, createUploadFactory, createUploadStore, createXHRTransport, deserializeSnapshot, fingerprintMatches, generateId, isRecord, multipartStrategy, resolveUploadConfig, serializeSnapshot, sleep, useOptionalUploadStore, useUploadStore, useUploader, useUploaderActions, validateFile, validateFileList, validateIntent };
|