uploader-sdk 1.0.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.
- package/README.md +477 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.js +407 -0
- package/dist/presigned-s3-adapter.d.ts +34 -0
- package/dist/presigned-s3-adapter.js +369 -0
- package/dist/react-hooks.d.ts +49 -0
- package/dist/react-hooks.js +344 -0
- package/package.json +74 -0
package/README.md
ADDED
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
# uploader-sdk
|
|
2
|
+
|
|
3
|
+
Browser upload SDK for React and web apps with IndexedDB staging, adapter-driven transport, parallel uploads, retries, pause/resume/cancel, and progress callbacks.
|
|
4
|
+
|
|
5
|
+
This README is written for teams adopting the SDK in production. It explains:
|
|
6
|
+
|
|
7
|
+
- What the SDK does and does not do
|
|
8
|
+
- What your team must manage
|
|
9
|
+
- Tradeoffs of the current architecture
|
|
10
|
+
- Operational and reliability guidance
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install uploader-sdk
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## TL;DR
|
|
19
|
+
|
|
20
|
+
- Use this SDK when you want upload orchestration in the browser.
|
|
21
|
+
- Keep auth, authorization, and storage policy in your upload service API.
|
|
22
|
+
- Use the built-in presigned S3 adapter or provide your own adapter.
|
|
23
|
+
|
|
24
|
+
## Current Version Scope
|
|
25
|
+
|
|
26
|
+
- Built-in provider support in this version is Amazon S3 using presigned URL flows.
|
|
27
|
+
- The included adapter (`uploader-sdk/adapters/presigned-s3`) expects service endpoints that issue presigned URLs for simple and multipart uploads.
|
|
28
|
+
- The SDK core is provider-agnostic, but non-S3 providers require your own custom adapter implementation.
|
|
29
|
+
- This package does not include direct server-side upload execution; uploads are performed by the browser to storage using service-issued signed URLs.
|
|
30
|
+
|
|
31
|
+
## Responsibility Model
|
|
32
|
+
|
|
33
|
+
### SDK responsibilities
|
|
34
|
+
|
|
35
|
+
- Stage files in IndexedDB.
|
|
36
|
+
- Enforce extension allow-list rules.
|
|
37
|
+
- Run concurrent uploads with retry support.
|
|
38
|
+
- Expose progress and lifecycle callbacks.
|
|
39
|
+
- Support pause, resume, cancel, and selected uploads.
|
|
40
|
+
- Trigger adapter cleanup on cancel or final failure.
|
|
41
|
+
|
|
42
|
+
### Upload service responsibilities
|
|
43
|
+
|
|
44
|
+
- Authenticate callers and authorize upload scope.
|
|
45
|
+
- Issue signed URLs or upload tokens.
|
|
46
|
+
- Validate file metadata and policy constraints.
|
|
47
|
+
- Verify object existence and integrity.
|
|
48
|
+
- Keep audit logs and operational metrics.
|
|
49
|
+
- Manage storage lifecycle (retention, deletion, compliance).
|
|
50
|
+
|
|
51
|
+
### Integrator responsibilities
|
|
52
|
+
|
|
53
|
+
- Build UX and business flow around the SDK.
|
|
54
|
+
- Configure retry and concurrency for your traffic profile.
|
|
55
|
+
- Decide extension allow-list policy.
|
|
56
|
+
- Handle callback-driven UI state and user messaging.
|
|
57
|
+
- Protect credentials and never expose service secrets in frontend code.
|
|
58
|
+
|
|
59
|
+
## Security Boundary
|
|
60
|
+
|
|
61
|
+
- The SDK is auth-agnostic by design.
|
|
62
|
+
- Authentication and authorization must be enforced by your upload service API.
|
|
63
|
+
- Signing credentials must stay on the server side.
|
|
64
|
+
- Do not commit real credentials to source control.
|
|
65
|
+
|
|
66
|
+
## Architecture Summary
|
|
67
|
+
|
|
68
|
+
High-level flow:
|
|
69
|
+
|
|
70
|
+
1. User selects files in browser.
|
|
71
|
+
2. SDK stages files in IndexedDB and returns staged metadata.
|
|
72
|
+
3. SDK starts uploads via selected adapter.
|
|
73
|
+
4. Adapter communicates with your upload service API.
|
|
74
|
+
5. Service API signs/transacts with storage provider.
|
|
75
|
+
6. SDK reports progress/retry/error/complete events.
|
|
76
|
+
7. SDK removes staged data on success or cancel.
|
|
77
|
+
|
|
78
|
+
## Tradeoffs and Design Decisions
|
|
79
|
+
|
|
80
|
+
### IndexedDB staging
|
|
81
|
+
|
|
82
|
+
Pros:
|
|
83
|
+
|
|
84
|
+
- Works for large files and queued uploads.
|
|
85
|
+
- Survives page-level state loss better than in-memory queues.
|
|
86
|
+
|
|
87
|
+
Tradeoffs:
|
|
88
|
+
|
|
89
|
+
- Browser quota limits apply.
|
|
90
|
+
- Data remains local until cleared.
|
|
91
|
+
- Some browser environments (private mode, strict policies) may reduce reliability.
|
|
92
|
+
|
|
93
|
+
### Adapter abstraction
|
|
94
|
+
|
|
95
|
+
Pros:
|
|
96
|
+
|
|
97
|
+
- Storage-provider agnostic SDK core.
|
|
98
|
+
- Easier to keep provider-specific logic outside business UI code.
|
|
99
|
+
|
|
100
|
+
Tradeoffs:
|
|
101
|
+
|
|
102
|
+
- Integrators must implement and maintain adapter semantics correctly.
|
|
103
|
+
- Runtime behavior quality depends on adapter implementation.
|
|
104
|
+
|
|
105
|
+
### Client retries
|
|
106
|
+
|
|
107
|
+
Pros:
|
|
108
|
+
|
|
109
|
+
- Better resilience to transient failures.
|
|
110
|
+
|
|
111
|
+
Tradeoffs:
|
|
112
|
+
|
|
113
|
+
- Can amplify backend load if too aggressive.
|
|
114
|
+
- Requires sane retry delay and concurrency limits.
|
|
115
|
+
|
|
116
|
+
### Allow-list only extension policy
|
|
117
|
+
|
|
118
|
+
Pros:
|
|
119
|
+
|
|
120
|
+
- Simple mental model and safer default when configured.
|
|
121
|
+
|
|
122
|
+
Tradeoffs:
|
|
123
|
+
|
|
124
|
+
- Files without an extension are rejected when allow-list is active.
|
|
125
|
+
- MIME spoofing is still possible; server-side validation remains mandatory.
|
|
126
|
+
|
|
127
|
+
## Quick Start (Core API)
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
import {
|
|
131
|
+
createUploadClient,
|
|
132
|
+
registerStorageAdapter,
|
|
133
|
+
setFileExtensionRules,
|
|
134
|
+
addFiles,
|
|
135
|
+
uploadFiles,
|
|
136
|
+
} from 'uploader-sdk';
|
|
137
|
+
|
|
138
|
+
const client = createUploadClient();
|
|
139
|
+
|
|
140
|
+
registerStorageAdapter(client, 'custom', {
|
|
141
|
+
async uploadFile(file, options = {}) {
|
|
142
|
+
// Call your upload service signing + upload flow here.
|
|
143
|
+
// Return URL string or detailed UploadResult.
|
|
144
|
+
return 'https://example.com/files/' + encodeURIComponent(file.name);
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
setFileExtensionRules(client, {
|
|
149
|
+
allowExtensions: ['jpg', 'png', 'pdf'],
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
await addFiles(client, selectedFiles);
|
|
153
|
+
|
|
154
|
+
await uploadFiles(client, 'custom', {
|
|
155
|
+
parallel: 3,
|
|
156
|
+
retry: 5,
|
|
157
|
+
retryDelayMs: 2000,
|
|
158
|
+
onProgress: (progress, fileName) => {
|
|
159
|
+
console.log(fileName, progress);
|
|
160
|
+
},
|
|
161
|
+
onRetry: (error, fileName, meta) => {
|
|
162
|
+
console.log('retry', fileName, meta.attempt, meta.maxRetries, error.message);
|
|
163
|
+
},
|
|
164
|
+
onComplete: (fileName, url) => {
|
|
165
|
+
console.log('uploaded', fileName, url);
|
|
166
|
+
},
|
|
167
|
+
onError: (error, fileName) => {
|
|
168
|
+
console.error('failed', fileName, error.code, error.message);
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## React Hook
|
|
174
|
+
|
|
175
|
+
Import from subpaths:
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
import { useUploader } from 'uploader-sdk/react';
|
|
179
|
+
import { createPresignedS3Adapter } from 'uploader-sdk/adapters/presigned-s3';
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
import { useUploader } from 'uploader-sdk/react';
|
|
184
|
+
import { createPresignedS3Adapter } from 'uploader-sdk/adapters/presigned-s3';
|
|
185
|
+
|
|
186
|
+
function UploadWidget() {
|
|
187
|
+
const uploader = useUploader({
|
|
188
|
+
adapterName: 's3',
|
|
189
|
+
adapter: createPresignedS3Adapter({
|
|
190
|
+
apiBaseUrl: 'http://localhost:8787',
|
|
191
|
+
multipartThresholdBytes: 20 * 1024 * 1024,
|
|
192
|
+
multipartPartSizeBytes: 8 * 1024 * 1024,
|
|
193
|
+
}),
|
|
194
|
+
defaultUploadOptions: {
|
|
195
|
+
parallel: 3,
|
|
196
|
+
retry: 5,
|
|
197
|
+
retryDelayMs: 2000,
|
|
198
|
+
},
|
|
199
|
+
rules: {
|
|
200
|
+
allowExtensions: ['jpg', 'png', 'pdf'],
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<>
|
|
206
|
+
<input
|
|
207
|
+
type="file"
|
|
208
|
+
multiple
|
|
209
|
+
onChange={async (e) => {
|
|
210
|
+
const selected = Array.from(e.target.files || []);
|
|
211
|
+
await uploader.addFiles(selected);
|
|
212
|
+
e.target.value = '';
|
|
213
|
+
}}
|
|
214
|
+
/>
|
|
215
|
+
<button onClick={() => void uploader.uploadAll()} disabled={uploader.isUploading}>
|
|
216
|
+
Upload All
|
|
217
|
+
</button>
|
|
218
|
+
</>
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Hook return shape:
|
|
224
|
+
|
|
225
|
+
- client
|
|
226
|
+
- files
|
|
227
|
+
- statusById
|
|
228
|
+
- logs
|
|
229
|
+
- isUploading
|
|
230
|
+
- refresh()
|
|
231
|
+
- addFiles(files)
|
|
232
|
+
- clearFiles()
|
|
233
|
+
- uploadAll(options?)
|
|
234
|
+
- uploadSelected(fileIds, options?)
|
|
235
|
+
- pause(fileId)
|
|
236
|
+
- resume(fileId)
|
|
237
|
+
- cancel(fileId)
|
|
238
|
+
- setRules(rules)
|
|
239
|
+
|
|
240
|
+
## Adapter Contract
|
|
241
|
+
|
|
242
|
+
Required adapter method:
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
interface StorageAdapter {
|
|
246
|
+
uploadFile(file: File, options?: Record<string, unknown>): Promise<string | UploadResult>;
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Optional adapter method:
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
cleanupUploadSession?(fileId: string, meta?: { reason: 'canceled' | 'final-failure' }): Promise<void>;
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Current packaged adapter:
|
|
257
|
+
|
|
258
|
+
- `uploader-sdk/adapters/presigned-s3` (S3 presigned URL strategy)
|
|
259
|
+
|
|
260
|
+
Common runtime options passed to adapter:
|
|
261
|
+
|
|
262
|
+
- fileId
|
|
263
|
+
- fileName
|
|
264
|
+
- fileSize
|
|
265
|
+
- fileType
|
|
266
|
+
- signal (AbortSignal)
|
|
267
|
+
- attempt
|
|
268
|
+
- onProgress(progress: number)
|
|
269
|
+
|
|
270
|
+
## Extension Rules
|
|
271
|
+
|
|
272
|
+
- If allowExtensions is provided, only those extensions are accepted.
|
|
273
|
+
- If allowExtensions is omitted, all extensions are accepted.
|
|
274
|
+
|
|
275
|
+
## Public API Surface
|
|
276
|
+
|
|
277
|
+
- createUploadClient(config?)
|
|
278
|
+
- registerStorageAdapter(client, name, adapter)
|
|
279
|
+
- setFileExtensionRules(client, rules)
|
|
280
|
+
- addFiles(client, files)
|
|
281
|
+
- listFiles(client)
|
|
282
|
+
- clearFiles(client)
|
|
283
|
+
- uploadFiles(client, adapterName, options?)
|
|
284
|
+
- uploadSelectedFiles(client, adapterName, fileIds, options?)
|
|
285
|
+
- pauseFileUpload(client, fileId)
|
|
286
|
+
- resumeFileUpload(client, fileId)
|
|
287
|
+
- cancelFileUpload(client, fileId)
|
|
288
|
+
|
|
289
|
+
## Error Model and Retry Semantics
|
|
290
|
+
|
|
291
|
+
Error codes:
|
|
292
|
+
|
|
293
|
+
- ADAPTER_NOT_FOUND
|
|
294
|
+
- UPLOAD_ABORTED
|
|
295
|
+
- UPLOAD_CANCELED
|
|
296
|
+
- UPLOAD_FAILED
|
|
297
|
+
- INDEXEDDB_ERROR
|
|
298
|
+
|
|
299
|
+
Retry behavior:
|
|
300
|
+
|
|
301
|
+
- onRetry fires for non-final failures.
|
|
302
|
+
- onError and onFinalError fire only after retries are exhausted.
|
|
303
|
+
- Pause-triggered abort does not consume retry budget.
|
|
304
|
+
- Cancel-triggered abort is treated as user intent and not surfaced as failure.
|
|
305
|
+
|
|
306
|
+
## Cancellation and Local Data Semantics
|
|
307
|
+
|
|
308
|
+
On cancel:
|
|
309
|
+
|
|
310
|
+
- Staged file is removed from IndexedDB.
|
|
311
|
+
- Adapter cleanup is invoked (best effort).
|
|
312
|
+
- For multipart uploads, local session metadata is removed when abort succeeds.
|
|
313
|
+
- If abort cannot be confirmed, session metadata may be retained for retryable cleanup.
|
|
314
|
+
|
|
315
|
+
## Operational Tuning Guidance
|
|
316
|
+
|
|
317
|
+
Recommended starting points:
|
|
318
|
+
|
|
319
|
+
- parallel: 2 to 4 for browser clients.
|
|
320
|
+
- retry: 3 to 5 for unstable networks.
|
|
321
|
+
- retryDelayMs: 500 to 2000 depending on backend limits.
|
|
322
|
+
- multipartPartSizeBytes: 8 MB to 16 MB for large uploads.
|
|
323
|
+
|
|
324
|
+
Tune with production metrics:
|
|
325
|
+
|
|
326
|
+
- Upload success rate
|
|
327
|
+
- P95/P99 upload latency
|
|
328
|
+
- Retry distribution
|
|
329
|
+
- 4xx vs 5xx failure split
|
|
330
|
+
- Abort cleanup success rate
|
|
331
|
+
|
|
332
|
+
## What Developers Must Manage
|
|
333
|
+
|
|
334
|
+
Frontend/app team:
|
|
335
|
+
|
|
336
|
+
- UX state, messaging, and retry affordances.
|
|
337
|
+
- File picker constraints and UX limits.
|
|
338
|
+
- Accessibility and localization of upload UI.
|
|
339
|
+
|
|
340
|
+
Service/backend team:
|
|
341
|
+
|
|
342
|
+
- AuthN/AuthZ
|
|
343
|
+
- Signing and storage policy
|
|
344
|
+
- CORS policy for upload endpoints
|
|
345
|
+
- Malware/content scanning if required
|
|
346
|
+
- Data retention and deletion lifecycle
|
|
347
|
+
- Compliance controls and auditability
|
|
348
|
+
|
|
349
|
+
SRE/platform team:
|
|
350
|
+
|
|
351
|
+
- Error budgets and alerting
|
|
352
|
+
- Capacity/rate limiting
|
|
353
|
+
- Incident runbooks
|
|
354
|
+
- Secret rotation and key hygiene
|
|
355
|
+
|
|
356
|
+
## Backend Contract v1 (for built-in presigned S3 adapter)
|
|
357
|
+
|
|
358
|
+
The managed upload service should expose:
|
|
359
|
+
|
|
360
|
+
1. POST /api/presign
|
|
361
|
+
Request:
|
|
362
|
+
- fileName: string
|
|
363
|
+
- contentType: string
|
|
364
|
+
- size: number
|
|
365
|
+
Response:
|
|
366
|
+
- assetId: string
|
|
367
|
+
- key: string
|
|
368
|
+
- uploadUrl: string
|
|
369
|
+
|
|
370
|
+
2. POST /api/multipart/start
|
|
371
|
+
Request:
|
|
372
|
+
- fileName: string
|
|
373
|
+
- contentType: string
|
|
374
|
+
- size: number
|
|
375
|
+
- partSize: number
|
|
376
|
+
Response:
|
|
377
|
+
- assetId: string
|
|
378
|
+
- key: string
|
|
379
|
+
- uploadId: string
|
|
380
|
+
- partSize: number
|
|
381
|
+
- totalParts: number
|
|
382
|
+
|
|
383
|
+
3. POST /api/multipart/sign-part
|
|
384
|
+
Request:
|
|
385
|
+
- key: string
|
|
386
|
+
- uploadId: string
|
|
387
|
+
- partNumber: number
|
|
388
|
+
Response:
|
|
389
|
+
- uploadUrl: string
|
|
390
|
+
|
|
391
|
+
4. GET /api/multipart/parts
|
|
392
|
+
Query:
|
|
393
|
+
- key: string
|
|
394
|
+
- uploadId: string
|
|
395
|
+
Response:
|
|
396
|
+
- parts: Array<{ PartNumber: number; ETag: string; Size?: number }>
|
|
397
|
+
|
|
398
|
+
5. POST /api/multipart/complete
|
|
399
|
+
Request:
|
|
400
|
+
- assetId: string
|
|
401
|
+
- key: string
|
|
402
|
+
- uploadId: string
|
|
403
|
+
- parts: Array<{ PartNumber: number; ETag: string }>
|
|
404
|
+
Response:
|
|
405
|
+
- assetId: string | null
|
|
406
|
+
- key: string
|
|
407
|
+
- etag?: string
|
|
408
|
+
|
|
409
|
+
6. POST /api/multipart/abort
|
|
410
|
+
Request:
|
|
411
|
+
- key: string
|
|
412
|
+
- uploadId: string
|
|
413
|
+
Response:
|
|
414
|
+
- ok: true
|
|
415
|
+
|
|
416
|
+
7. POST /api/verify
|
|
417
|
+
Request:
|
|
418
|
+
- assetId: string
|
|
419
|
+
- key: string
|
|
420
|
+
- size: number
|
|
421
|
+
- contentType: string
|
|
422
|
+
Response:
|
|
423
|
+
- verified: boolean
|
|
424
|
+
|
|
425
|
+
8. GET /api/download-url
|
|
426
|
+
Query:
|
|
427
|
+
- key: string
|
|
428
|
+
- assetId: string
|
|
429
|
+
Response:
|
|
430
|
+
- url: string
|
|
431
|
+
|
|
432
|
+
## Failure Modes You Should Expect
|
|
433
|
+
|
|
434
|
+
- User closes tab mid-upload.
|
|
435
|
+
- Network flaps during multipart part transfer.
|
|
436
|
+
- Signed URL expiry during slow uploads.
|
|
437
|
+
- CORS misconfiguration blocking ETag visibility.
|
|
438
|
+
- Service unavailable during abort cleanup.
|
|
439
|
+
|
|
440
|
+
Plan for these with retries, user messaging, and operational alerts.
|
|
441
|
+
|
|
442
|
+
## Testing Strategy
|
|
443
|
+
|
|
444
|
+
Local CI checks:
|
|
445
|
+
|
|
446
|
+
- npm run test:ci
|
|
447
|
+
- npm run release:check
|
|
448
|
+
|
|
449
|
+
Optional live integration against real service and S3:
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
LIVE_S3_INTEGRATION=1 LIVE_API_BASE_URL=http://localhost:8787 npm run test:live
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
Live check validates:
|
|
456
|
+
|
|
457
|
+
- /health availability
|
|
458
|
+
- end-to-end simple upload contract
|
|
459
|
+
- multipart abort cleanup path
|
|
460
|
+
|
|
461
|
+
By default npm run test:live is a no-op unless LIVE_S3_INTEGRATION=1 is set.
|
|
462
|
+
|
|
463
|
+
## Package Contents
|
|
464
|
+
|
|
465
|
+
Published package includes:
|
|
466
|
+
|
|
467
|
+
- dist/*
|
|
468
|
+
- README.md
|
|
469
|
+
- package.json
|
|
470
|
+
|
|
471
|
+
Source, app demo, backend example, tests, scripts, and .env are not part of published artifacts.
|
|
472
|
+
|
|
473
|
+
## Notes
|
|
474
|
+
|
|
475
|
+
- This package is browser-oriented and uses IndexedDB.
|
|
476
|
+
- Signing, auth, and storage policy belong to your managed upload service.
|
|
477
|
+
- Keep secrets server-side and rotate credentials if they are ever exposed.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
export type UploadResult = {
|
|
2
|
+
url: string;
|
|
3
|
+
assetId?: string;
|
|
4
|
+
key?: string;
|
|
5
|
+
verified?: boolean;
|
|
6
|
+
};
|
|
7
|
+
export type UploadErrorCode = 'ADAPTER_NOT_FOUND' | 'UPLOAD_ABORTED' | 'UPLOAD_CANCELED' | 'UPLOAD_FAILED' | 'INDEXEDDB_ERROR';
|
|
8
|
+
export type UploadError = Error & {
|
|
9
|
+
code: UploadErrorCode;
|
|
10
|
+
retriable?: boolean;
|
|
11
|
+
cause?: unknown;
|
|
12
|
+
};
|
|
13
|
+
export interface StorageAdapter {
|
|
14
|
+
uploadFile(file: File, options?: Record<string, unknown>): Promise<string | UploadResult>;
|
|
15
|
+
cleanupUploadSession?: (fileId: string, meta?: {
|
|
16
|
+
reason: 'canceled' | 'final-failure';
|
|
17
|
+
}) => Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
export type ExtensionRules = {
|
|
20
|
+
allowExtensions?: string[];
|
|
21
|
+
};
|
|
22
|
+
export type UploadOptions = {
|
|
23
|
+
parallel?: number;
|
|
24
|
+
retry?: number;
|
|
25
|
+
retryDelayMs?: number;
|
|
26
|
+
onProgress?: (progress: number, fileName: string, meta?: {
|
|
27
|
+
fileId: string;
|
|
28
|
+
}) => void;
|
|
29
|
+
onRetry?: (error: UploadError, fileName: string, meta: {
|
|
30
|
+
attempt: number;
|
|
31
|
+
maxRetries: number;
|
|
32
|
+
fileId: string;
|
|
33
|
+
}) => void;
|
|
34
|
+
onError?: (error: UploadError, fileName: string, meta?: {
|
|
35
|
+
fileId: string;
|
|
36
|
+
}) => void;
|
|
37
|
+
onFinalError?: (error: UploadError, fileName: string, meta?: {
|
|
38
|
+
fileId: string;
|
|
39
|
+
}) => void;
|
|
40
|
+
onComplete?: (fileName: string, url: string, meta?: {
|
|
41
|
+
fileId: string;
|
|
42
|
+
}) => void;
|
|
43
|
+
onCompleteDetailed?: (fileName: string, result: UploadResult, meta?: {
|
|
44
|
+
fileId: string;
|
|
45
|
+
}) => void;
|
|
46
|
+
};
|
|
47
|
+
export declare function createUploadError(code: UploadErrorCode, message: string, options?: {
|
|
48
|
+
retriable?: boolean;
|
|
49
|
+
cause?: unknown;
|
|
50
|
+
}): UploadError;
|
|
51
|
+
export declare class UploadSDK {
|
|
52
|
+
private adapters;
|
|
53
|
+
private dbName;
|
|
54
|
+
private storeName;
|
|
55
|
+
private allowExtensions;
|
|
56
|
+
private pausedFileIds;
|
|
57
|
+
private canceledFileIds;
|
|
58
|
+
private activeControllers;
|
|
59
|
+
constructor(config?: {
|
|
60
|
+
dbName?: string;
|
|
61
|
+
storeName?: string;
|
|
62
|
+
});
|
|
63
|
+
registerAdapter(name: string, adapter: StorageAdapter): void;
|
|
64
|
+
setExtensionRules(rules: ExtensionRules): void;
|
|
65
|
+
pauseUpload(fileId: string): void;
|
|
66
|
+
resumeUpload(fileId: string): void;
|
|
67
|
+
cancelUpload(fileId: string): Promise<void>;
|
|
68
|
+
saveFilesToIndexedDB(files: File[]): Promise<{
|
|
69
|
+
saved: string[];
|
|
70
|
+
rejected: string[];
|
|
71
|
+
}>;
|
|
72
|
+
listStoredFiles(): Promise<Array<{
|
|
73
|
+
id: string;
|
|
74
|
+
name: string;
|
|
75
|
+
size: number;
|
|
76
|
+
type: string;
|
|
77
|
+
}>>;
|
|
78
|
+
clearStoredFiles(): Promise<void>;
|
|
79
|
+
uploadFiles(adapterName: string, options?: UploadOptions): Promise<void>;
|
|
80
|
+
uploadSelectedFiles(adapterName: string, fileIds: string[], options?: UploadOptions): Promise<void>;
|
|
81
|
+
private uploadWithConcurrency;
|
|
82
|
+
private uploadSingleWithRetry;
|
|
83
|
+
private waitIfPaused;
|
|
84
|
+
private prepareUploadItems;
|
|
85
|
+
private removeStoredFileById;
|
|
86
|
+
private isFileAllowed;
|
|
87
|
+
private extractExtension;
|
|
88
|
+
private normalizeExtension;
|
|
89
|
+
private buildFileId;
|
|
90
|
+
private openDB;
|
|
91
|
+
private requestToPromise;
|
|
92
|
+
private txComplete;
|
|
93
|
+
private sleep;
|
|
94
|
+
private isAbortError;
|
|
95
|
+
private normalizeUploadError;
|
|
96
|
+
private cleanupAdapterSession;
|
|
97
|
+
private cleanupAllAdapterSessions;
|
|
98
|
+
}
|
|
99
|
+
export type UploadClient = UploadSDK;
|
|
100
|
+
export declare function createUploadClient(config?: {
|
|
101
|
+
dbName?: string;
|
|
102
|
+
storeName?: string;
|
|
103
|
+
}): UploadClient;
|
|
104
|
+
export declare function registerStorageAdapter(client: UploadClient, name: string, adapter: StorageAdapter): void;
|
|
105
|
+
export declare function setFileExtensionRules(client: UploadClient, rules: ExtensionRules): void;
|
|
106
|
+
export declare function addFiles(client: UploadClient, files: File[]): Promise<{
|
|
107
|
+
saved: string[];
|
|
108
|
+
rejected: string[];
|
|
109
|
+
}>;
|
|
110
|
+
export declare function listFiles(client: UploadClient): Promise<Array<{
|
|
111
|
+
id: string;
|
|
112
|
+
name: string;
|
|
113
|
+
size: number;
|
|
114
|
+
type: string;
|
|
115
|
+
}>>;
|
|
116
|
+
export declare function clearFiles(client: UploadClient): Promise<void>;
|
|
117
|
+
export declare function uploadFiles(client: UploadClient, adapterName: string, options?: UploadOptions): Promise<void>;
|
|
118
|
+
export declare function uploadSelectedFiles(client: UploadClient, adapterName: string, fileIds: string[], options?: UploadOptions): Promise<void>;
|
|
119
|
+
export declare function pauseFileUpload(client: UploadClient, fileId: string): void;
|
|
120
|
+
export declare function resumeFileUpload(client: UploadClient, fileId: string): void;
|
|
121
|
+
export declare function cancelFileUpload(client: UploadClient, fileId: string): Promise<void>;
|