@gentleduck/upload 0.2.5 → 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 (129) hide show
  1. package/README.md +297 -0
  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 -90
  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/__tests__/emitter.test.ts +85 -0
  18. package/src/__tests__/fingerprint.test.ts +49 -0
  19. package/src/__tests__/guards.test.ts +40 -0
  20. package/src/__tests__/id.test.ts +67 -0
  21. package/src/__tests__/mime-sniff.test.ts +142 -0
  22. package/src/__tests__/persistence.test.ts +191 -0
  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/__tests__/store-libs.test.ts +192 -0
  27. package/src/__tests__/transport-fetch.test.ts +108 -0
  28. package/src/__tests__/transport-libs.test.ts +42 -0
  29. package/src/__tests__/transport.test.ts +182 -0
  30. package/src/core/__tests__/errors.test.ts +152 -0
  31. package/src/core/client.ts +3 -0
  32. package/src/core/contracts/contracts.types.ts +373 -0
  33. package/src/core/contracts/index.ts +3 -8
  34. package/src/core/contracts/transport/index.ts +3 -2
  35. package/src/core/contracts/transport/transport.fetch.ts +203 -0
  36. package/src/core/contracts/transport/transport.libs.ts +13 -39
  37. package/src/core/contracts/transport/transport.ts +96 -90
  38. package/src/core/contracts/transport/transport.types.ts +71 -35
  39. package/src/core/engine/__tests__/config-nan-bypass.test.ts +40 -0
  40. package/src/core/engine/engine.libs.ts +35 -0
  41. package/src/core/engine/engine.types.ts +490 -0
  42. package/src/core/engine/index.ts +3 -8
  43. package/src/core/engine/reducer.ts +93 -53
  44. package/src/core/engine/store/handlers/add-file.ts +43 -48
  45. package/src/core/engine/store/handlers/cancel.ts +13 -8
  46. package/src/core/engine/store/handlers/clean-up.ts +11 -8
  47. package/src/core/engine/store/handlers/create-intent.ts +82 -27
  48. package/src/core/engine/store/handlers/finalize.ts +30 -13
  49. package/src/core/engine/store/handlers/index.ts +7 -7
  50. package/src/core/engine/store/handlers/pause.ts +8 -6
  51. package/src/core/engine/store/handlers/run-upload.ts +54 -39
  52. package/src/core/engine/store/index.ts +27 -21
  53. package/src/core/engine/store/store.dispatch.ts +10 -8
  54. package/src/core/engine/store/store.libs.ts +197 -94
  55. package/src/core/engine/store/store.runtime.ts +52 -53
  56. package/src/core/engine/store/store.schedule.ts +27 -21
  57. package/src/core/engine/store/store.types.ts +177 -227
  58. package/src/core/engine/validation/__tests__/intent.test.ts +70 -0
  59. package/src/core/engine/validation/file.ts +8 -4
  60. package/src/core/engine/validation/index.ts +1 -0
  61. package/src/core/engine/validation/intent.ts +49 -27
  62. package/src/core/engine/validation/list.ts +14 -15
  63. package/src/core/engine/validation/mime.ts +39 -0
  64. package/src/core/errors.ts +271 -0
  65. package/src/core/index.ts +28 -5
  66. package/src/core/persistence/__tests__/deserialize-nan-bypass.test.ts +100 -0
  67. package/src/core/persistence/__tests__/persistence.test.ts +85 -0
  68. package/src/core/persistence/adapters.indexeddb.ts +9 -3
  69. package/src/core/persistence/adapters.local.ts +9 -3
  70. package/src/core/persistence/adapters.memory.ts +35 -13
  71. package/src/core/persistence/index.ts +5 -5
  72. package/src/core/persistence/persistence.ts +73 -60
  73. package/src/core/persistence/persistence.types.ts +140 -60
  74. package/src/core/utils/__tests__/guards.test.ts +93 -0
  75. package/src/core/utils/__tests__/url-safety.test.ts +112 -0
  76. package/src/core/utils/async.ts +7 -2
  77. package/src/core/utils/constants.ts +3 -9
  78. package/src/core/utils/emitter/emitter.ts +126 -0
  79. package/src/core/utils/emitter/emitter.types.ts +33 -16
  80. package/src/core/utils/emitter/index.ts +2 -74
  81. package/src/core/utils/fingerprint.ts +16 -5
  82. package/src/core/utils/guards.ts +91 -1
  83. package/src/core/utils/hash/__tests__/sha256.test.ts +61 -0
  84. package/src/core/utils/hash/index.ts +126 -0
  85. package/src/core/utils/hash/sha256.ts +179 -0
  86. package/src/core/utils/id.ts +33 -1
  87. package/src/core/utils/index.ts +15 -6
  88. package/src/core/utils/mime-sniff.ts +119 -0
  89. package/src/core/utils/sanitize-filename.ts +85 -0
  90. package/src/core/utils/url-safety.ts +156 -0
  91. package/src/react/__tests__/use-dropzone.test.ts +64 -0
  92. package/src/react/index.ts +5 -2
  93. package/src/react/upload-provider.tsx +59 -95
  94. package/src/react/uploader.types.ts +80 -0
  95. package/src/react/use-dropzone.tsx +226 -0
  96. package/src/react/use-uploader.tsx +97 -93
  97. package/src/strategies/_shared/__tests__/retry.test.ts +120 -0
  98. package/src/strategies/_shared/retry.ts +79 -0
  99. package/src/strategies/index.ts +9 -15
  100. package/src/strategies/multipart/__tests__/multipart.test.ts +229 -0
  101. package/src/strategies/multipart/index.ts +211 -116
  102. package/src/strategies/post/__tests__/post-url-safety.test.ts +119 -0
  103. package/src/strategies/post/index.ts +113 -71
  104. package/src/strategies/put/__tests__/put.test.ts +132 -0
  105. package/src/strategies/put/index.ts +139 -0
  106. package/src/strategies/registry/index.ts +12 -9
  107. package/src/strategies/tus/__tests__/tus.test.ts +159 -0
  108. package/src/strategies/tus/index.ts +211 -0
  109. package/dist/async-DxRWu4le.js +0 -1
  110. package/dist/core-BNxznRif.js +0 -2
  111. package/dist/index-BXg9WIce.d.ts +0 -987
  112. package/dist/strategy.types-gg9ZStRe.d.ts +0 -225
  113. package/src/core/client/config.types.ts +0 -77
  114. package/src/core/client/index.ts +0 -4
  115. package/src/core/client/plugins.types.ts +0 -46
  116. package/src/core/client/retry.types.ts +0 -6
  117. package/src/core/client/uploadClient.ts +0 -19
  118. package/src/core/contracts/backendApi.ts +0 -62
  119. package/src/core/contracts/cursor.types.ts +0 -23
  120. package/src/core/contracts/errors.types.ts +0 -67
  121. package/src/core/contracts/fingerprint.types.ts +0 -18
  122. package/src/core/contracts/intent.types.ts +0 -39
  123. package/src/core/contracts/result.types.ts +0 -11
  124. package/src/core/contracts/strategy.types.ts +0 -45
  125. package/src/core/engine/commands.types.ts +0 -17
  126. package/src/core/engine/event-map.types.ts +0 -45
  127. package/src/core/engine/internal-events.types.ts +0 -222
  128. package/src/core/engine/outcome.types.ts +0 -9
  129. package/src/core/engine/progress.types.ts +0 -15
@@ -0,0 +1,490 @@
1
+ import type { Contracts } from '../contracts/contracts.types'
2
+ import type { UploadError } from '../errors'
3
+ import type { Store } from './store'
4
+
5
+ /**
6
+ * Engine-level type surface containing runtime state models, commands, progress,
7
+ * and configuration options.
8
+ * @author wildduck2 <https://github.com/wildduck2>
9
+ */
10
+ export namespace Engine {
11
+ /**
12
+ * Return value from a retry policy determining if and when a task should be re-scheduled.
13
+ */
14
+ export type RetryDecision =
15
+ | {
16
+ /** The task has failed terminal or cannot recover. */
17
+ retryable: false
18
+ }
19
+ | {
20
+ /** The task is recoverable and should retry. */
21
+ retryable: true
22
+ /** Delay duration in milliseconds before invoking the next attempt. */
23
+ delayMs: number
24
+ }
25
+
26
+ /**
27
+ * Global upload engine configuration.
28
+ *
29
+ * Coordinates concurrency limits, retry strategies, constraints, and validation.
30
+ *
31
+ * @typeParam P - Union of allowed `purpose` strings for your app (e.g. `"avatar" | "attachment"`).
32
+ */
33
+ export type Config<P extends string> = {
34
+ /**
35
+ * Maximum number of parallel uploads active at any time.
36
+ * Queued items wait until active uploads complete or fail.
37
+ */
38
+ maxConcurrentUploads: number
39
+
40
+ /**
41
+ * Auto-start uploads for specific purposes.
42
+ * - Array form: only files with these purposes automatically begin uploading on registration.
43
+ * - Function form: dynamic callback determining whether to auto-start.
44
+ */
45
+ autoStart?: (readonly P[] | ((purpose: P) => boolean)) | undefined
46
+
47
+ /**
48
+ * Throttle delay in milliseconds for progress events.
49
+ * Limits rendering updates and state changes under busy progress flows.
50
+ */
51
+ progressThrottleMs: number
52
+
53
+ /**
54
+ * Validation rules keyed by purpose.
55
+ */
56
+ validation: Partial<Record<P, Contracts.ValidationRules>>
57
+
58
+ /**
59
+ * Maximum number of retry attempts permitted for upload/intent actions.
60
+ */
61
+ maxAttempts: number
62
+
63
+ /**
64
+ * Custom retry policy handler.
65
+ * Overrides default exponential backoff calculation.
66
+ */
67
+ retryPolicy?:
68
+ | ((ctx: {
69
+ /** The active execution phase. */
70
+ phase: 'intent' | 'upload' | 'complete'
71
+ /** Current attempt number (starting at 1). */
72
+ attempt: number
73
+ /** The normalized error structure. */
74
+ error: UploadError
75
+ }) => RetryDecision)
76
+ | undefined
77
+
78
+ /**
79
+ * Maximum number of items to keep in memory/state.
80
+ * When exceeded, oldest completed/canceled items are evicted automatically.
81
+ *
82
+ * Set to `undefined` for no limit (not recommended for long-running single-page apps).
83
+ */
84
+ maxItems: number
85
+
86
+ /**
87
+ * Duration in milliseconds after which completed items are evicted from the store.
88
+ * Set to `undefined` to preserve completed items indefinitely.
89
+ */
90
+ completedItemTTL?: number | undefined
91
+
92
+ /**
93
+ * Set to `true` to validate files by sniffing magic bytes/mime signature
94
+ * and rejecting files whose suffix does not match structural magic numbers.
95
+ */
96
+ strictMimeMatch?: boolean | undefined
97
+
98
+ /**
99
+ * File-size boundary in bytes between the two checksum paths. At or below
100
+ * it, files hash inline with native Web Crypto (fastest). Above it, files
101
+ * hash incrementally in bounded slices — off the main thread via a Web
102
+ * Worker when available — so large files no longer freeze the UI and are
103
+ * still deduplicated. Set to `null` or `undefined` for the default (64 MiB).
104
+ */
105
+ checksumMaxSize?: number | null | undefined
106
+ }
107
+
108
+ /**
109
+ * Upload progress snapshot.
110
+ */
111
+ export type Progress = {
112
+ /** Bytes uploaded so far. */
113
+ uploadedBytes: number
114
+ /** Total bytes to upload. */
115
+ totalBytes: number
116
+ /** Percent complete (0..100). */
117
+ pct: number
118
+ }
119
+
120
+ /**
121
+ * Describes how a `completed` upload item resolved.
122
+ * - `'upload'`: standard byte transfer.
123
+ * - `'dedupe'`: server matched existing file checksum, skipping byte transfer.
124
+ */
125
+ export type CompletionKind = 'upload' | 'dedupe'
126
+
127
+ /**
128
+ * Terminal outcome returned by `waitFor`.
129
+ *
130
+ * @template R Result type carried on successful completion.
131
+ */
132
+ export type Outcome<R extends Contracts.Result.Base> =
133
+ | {
134
+ localId: string
135
+ status: 'completed'
136
+ completedBy: CompletionKind
137
+ result: R
138
+ }
139
+ | {
140
+ localId: string
141
+ status: 'error'
142
+ error: UploadError
143
+ }
144
+ | {
145
+ localId: string
146
+ status: 'canceled'
147
+ }
148
+ | {
149
+ localId: string
150
+ status: 'missing'
151
+ /**
152
+ * Why the id is missing.
153
+ * - `'removed'`: explicit user removal.
154
+ * - `'evicted'`: automatically removed (maxItems/TTL rules).
155
+ * - `'never-existed'`: id was never registered.
156
+ * - `'destroyed'`: store was destroyed.
157
+ */
158
+ reason: 'removed' | 'evicted' | 'never-existed' | 'destroyed'
159
+ }
160
+
161
+ /**
162
+ * Public commands dispatched to the upload store.
163
+ *
164
+ * @template P Purpose discriminator string.
165
+ */
166
+ export type Command<P extends string> =
167
+ | {
168
+ /** Register files into the upload store for a specific purpose. */
169
+ type: 'addFiles'
170
+ files: File[]
171
+ purpose: P
172
+ /** Optional caller metadata forwarded to every backend API call for this file. */
173
+ meta?: Record<string, unknown> | undefined
174
+ }
175
+ | {
176
+ /** Start uploading a specific file. */
177
+ type: 'start'
178
+ localId: string
179
+ }
180
+ | {
181
+ /** Start all queued files, optionally filtering by purpose. */
182
+ type: 'startAll'
183
+ purpose?: P
184
+ }
185
+ | {
186
+ /** Pause an active upload. */
187
+ type: 'pause'
188
+ localId: string
189
+ }
190
+ | {
191
+ /** Pause all active uploads, optionally filtering by purpose. */
192
+ type: 'pauseAll'
193
+ purpose?: P
194
+ }
195
+ | {
196
+ /** Resume a paused upload. */
197
+ type: 'resume'
198
+ localId: string
199
+ }
200
+ | {
201
+ /** Cancel a pending or active upload. */
202
+ type: 'cancel'
203
+ localId: string
204
+ }
205
+ | {
206
+ /** Cancel all pending and active uploads, optionally filtering by purpose. */
207
+ type: 'cancelAll'
208
+ purpose?: P
209
+ }
210
+ | {
211
+ /** Retry a failed upload item. */
212
+ type: 'retry'
213
+ localId: string
214
+ }
215
+ | {
216
+ /** Re-bind a new browser `File` object to a resumed/paused item missing a file reference. */
217
+ type: 'rebind'
218
+ localId: string
219
+ file: File
220
+ }
221
+ | {
222
+ /** Remove an item from the store state entirely. */
223
+ type: 'remove'
224
+ localId: string
225
+ }
226
+
227
+ /**
228
+ * Const mapping of upload stages.
229
+ */
230
+ export const Phases = {
231
+ /** Initial validation checks are running. */
232
+ validating: 'validating',
233
+ /** Fetching signed URLs and strategies from backend. */
234
+ creating_intent: 'creating_intent',
235
+ /** Ready to start uploading bytes. */
236
+ ready: 'ready',
237
+ /** Waiting in queue (concurrency cap reached). */
238
+ queued: 'queued',
239
+ /** Actively transferring bytes. */
240
+ uploading: 'uploading',
241
+ /** Upload paused; resumable state preserved. */
242
+ paused: 'paused',
243
+ /** Triggering backend finalization. */
244
+ completing: 'completing',
245
+ /** File is fully completed and registered on backend. */
246
+ completed: 'completed',
247
+ /** Execution hit a terminal error or maximum retry cap. */
248
+ error: 'error',
249
+ /** Upload was canceled by the user. */
250
+ canceled: 'canceled',
251
+ } as const
252
+
253
+ /** Every upload phase; the `phase` discriminator of {@link Item}. */
254
+ export type Phase = keyof typeof Phases
255
+
256
+ interface BaseItem<P extends string> {
257
+ /** Unique client-side identifier for this file item. */
258
+ localId: string
259
+ /** Target upload purpose. */
260
+ purpose: P
261
+ /** Metadata properties identifying the file. */
262
+ fingerprint: Contracts.FingerprintFile
263
+ /** Epoch timestamp in ms when the item was registered. */
264
+ createdAt: number
265
+ attempt?: number | undefined
266
+ file?: File | undefined
267
+ /** Full phase history. Each entry records when a phase was entered/left and any stripped error. */
268
+ steps: Contracts.UploadStep[]
269
+ /** Arbitrary caller-supplied metadata from the addFiles command. Never persisted. */
270
+ meta: Record<string, unknown>
271
+ }
272
+
273
+ /**
274
+ * Representational union of upload items in their respective lifecycle phases.
275
+ */
276
+ export type Item<
277
+ M extends Contracts.Intent.Map,
278
+ C extends Contracts.Cursor.Map<M>,
279
+ P extends string,
280
+ R extends Contracts.Result.Base = Contracts.Result.Base,
281
+ > = BaseItem<P> &
282
+ (
283
+ | { phase: 'validating'; file: File }
284
+ | { phase: 'creating_intent'; file: File; attempt: number }
285
+ | {
286
+ phase: 'ready'
287
+ file: File
288
+ intent: Contracts.Intent.Any<M>
289
+ cursor?: Contracts.Cursor.Any<C> | undefined
290
+ progress?: Progress | undefined
291
+ }
292
+ | {
293
+ phase: 'queued'
294
+ file: File
295
+ intent: Contracts.Intent.Any<M>
296
+ requestedAt: number
297
+ cursor?: Contracts.Cursor.Any<C> | undefined
298
+ progress?: Progress | undefined
299
+ }
300
+ | {
301
+ phase: 'uploading'
302
+ file: File
303
+ intent: Contracts.Intent.Any<M>
304
+ startedAt: number
305
+ progress: Progress
306
+ cursor?: Contracts.Cursor.Any<C> | undefined
307
+ }
308
+ | {
309
+ phase: 'paused'
310
+ intent: Contracts.Intent.Any<M>
311
+ cursor: Contracts.Cursor.Any<C>
312
+ progress: Progress
313
+ pausedAt: number
314
+ file?: File | undefined
315
+ }
316
+ | { phase: 'completing'; file: File; intent: Contracts.Intent.Any<M>; progress: Progress; completingAt: number }
317
+ | {
318
+ phase: 'completed'
319
+ completedBy: CompletionKind
320
+ result: R
321
+ completedAt: number
322
+ intent?: Contracts.Intent.Any<M> | undefined
323
+ file?: File | undefined
324
+ }
325
+ | {
326
+ phase: 'error'
327
+ error: UploadError
328
+ retryable: boolean
329
+ attempt: number
330
+ failedAt: number
331
+ file?: File | undefined
332
+ intent?: Contracts.Intent.Any<M> | undefined
333
+ cursor?: Contracts.Cursor.Any<C> | undefined
334
+ progress?: Progress | undefined
335
+ }
336
+ | {
337
+ phase: 'canceled'
338
+ canceledAt: number
339
+ file?: File | undefined
340
+ intent?: Contracts.Intent.Any<M> | undefined
341
+ cursor?: Contracts.Cursor.Any<C> | undefined
342
+ progress?: Progress | undefined
343
+ attempt?: number | undefined
344
+ }
345
+ )
346
+
347
+ /**
348
+ * Immutable state shape of the upload engine store.
349
+ */
350
+ export type State<
351
+ M extends Contracts.Intent.Map,
352
+ C extends Contracts.Cursor.Map<M>,
353
+ P extends string,
354
+ R extends Contracts.Result.Base = Contracts.Result.Base,
355
+ > = {
356
+ /** Map of active and historical upload items. */
357
+ items: Map<string, Item<M, C, P, R>>
358
+ }
359
+
360
+ /**
361
+ * Interface for registering lifecycle plugins.
362
+ */
363
+ export type Plugin<
364
+ M extends Contracts.Intent.Map,
365
+ C extends Contracts.Cursor.Map<M>,
366
+ P extends string,
367
+ R extends Contracts.Result.Base = Contracts.Result.Base,
368
+ > = {
369
+ /** Name of the plugin (for diagnostics). */
370
+ name: string
371
+ /** Sets up subscription listener binds on the store core proxy. */
372
+ setup(store: Pick<Store.UploadStore<M, C, P, R>, 'on' | 'off' | 'dispatch' | 'getSnapshot'>): void
373
+ }
374
+
375
+ /**
376
+ * Events emitted by effects and consumed by the reducer to transition item states.
377
+ */
378
+ export type Event<
379
+ M extends Contracts.Intent.Map,
380
+ C extends Contracts.Cursor.Map<M>,
381
+ P extends string,
382
+ R extends Contracts.Result.Base = Contracts.Result.Base,
383
+ > =
384
+ | {
385
+ type: 'files.added'
386
+ items: Array<{
387
+ localId: string
388
+ purpose: P
389
+ file: File
390
+ fingerprint: Contracts.FingerprintFile
391
+ createdAt: number
392
+ meta: Record<string, unknown>
393
+ }>
394
+ }
395
+ | { type: 'fingerprint.updated'; localId: string; fingerprint: Contracts.FingerprintFile }
396
+ | { type: 'validation.ok'; localId: string }
397
+ | { type: 'validation.failed'; localId: string; reason: Contracts.Validation.Rejection }
398
+ | { type: 'intent.ok'; localId: string; intent: Contracts.Intent.Any<M> }
399
+ | { type: 'intent.failed'; localId: string; error: UploadError; retryable: boolean }
400
+ | { type: 'upload.begin'; localId: string; startedAt: number }
401
+ | { type: 'upload.progress'; localId: string; uploadedBytes: number; totalBytes: number }
402
+ | { type: 'cursor.updated'; localId: string; cursor: Contracts.Cursor.Any<C> }
403
+ | { type: 'upload.ok'; localId: string }
404
+ | { type: 'upload.failed'; localId: string; error: UploadError; retryable: boolean }
405
+ | { type: 'dedupe.ok'; localId: string; result: R }
406
+ | { type: 'complete.ok'; localId: string; result: R }
407
+ | { type: 'complete.failed'; localId: string; error: UploadError; retryable: boolean }
408
+ | { type: 'paused'; localId: string; cursor: Contracts.Cursor.Any<C>; pausedAt: number }
409
+ | { type: 'canceled'; localId: string; canceledAt: number }
410
+
411
+ /**
412
+ * Public event registry mapping event names to payloads emitted via `store.on()`.
413
+ */
414
+ export type EventMap<
415
+ M extends Contracts.Intent.Map,
416
+ C extends Contracts.Cursor.Map<M>,
417
+ P extends string,
418
+ R extends Contracts.Result.Base = Contracts.Result.Base,
419
+ > = {
420
+ /** Emitted when a file is validated and successfully registered in state. */
421
+ 'file.added': { localId: string; purpose: P; file: File; fingerprint: Contracts.FingerprintFile }
422
+ /** Emitted when a file fails client-side validation rules. */
423
+ 'file.rejected': { file: File; reason: Contracts.Validation.Rejection }
424
+
425
+ /** Emitted when validation succeeds. */
426
+ 'validation.ok': { localId: string }
427
+ /** Emitted when validation fails. */
428
+ 'validation.failed': { localId: string; reason: Contracts.Validation.Rejection }
429
+
430
+ /** Emitted when intent lookup/creation is requested. */
431
+ 'intent.creating': { localId: string }
432
+ /** Emitted when upload intent is successfully created. */
433
+ 'intent.created': { localId: string; intent: M[keyof M] }
434
+ /** Emitted when intent creation fails. */
435
+ 'intent.failed': { localId: string; error: UploadError; retryable: boolean }
436
+
437
+ /** Emitted when an item is queued waiting for concurrency slots. */
438
+ 'upload.queued': { localId: string }
439
+ /** Emitted when a paused upload is resumed. */
440
+ 'upload.resumed': { localId: string }
441
+ /** Emitted when data transfer starts. */
442
+ 'upload.started': { localId: string }
443
+ /** Periodic progress event. */
444
+ 'upload.progress': { localId: string; pct: number; uploadedBytes: number; totalBytes: number }
445
+ /** Emitted when strategy cursor state is updated. */
446
+ 'upload.cursor': { localId: string; cursor: Contracts.Cursor.Any<C> }
447
+ /** Emitted when upload is paused. */
448
+ 'upload.paused': { localId: string; cursor: Contracts.Cursor.Any<C> }
449
+ /** Emitted when upload is canceled. */
450
+ 'upload.canceled': { localId: string }
451
+
452
+ /** Emitted when final completing steps (like completeMultipart or final verification) begin. */
453
+ 'upload.completing': { localId: string }
454
+ /** Emitted when a file is completely uploaded and finalized. */
455
+ 'upload.completed': { localId: string; result: R; completedBy: CompletionKind }
456
+
457
+ /** Emitted when transfer hits a retryable or terminal error. */
458
+ 'upload.error': { localId: string; error: UploadError; retryable: boolean }
459
+
460
+ /** Emitted when an item is removed from the store state. */
461
+ 'upload.removed': { localId: string; reason: 'user' | 'cleanup' }
462
+
463
+ /** Emitted when a file rebind operation succeeds. */
464
+ 'rebind.ok': { localId: string }
465
+ /** Emitted when a file rebind fails. */
466
+ 'rebind.failed': { localId: string; reason: RebindReason }
467
+ }
468
+
469
+ /**
470
+ * Rebind failure classifications.
471
+ */
472
+ export type RebindReason =
473
+ | { code: 'no_item' }
474
+ | { code: 'wrong_phase'; phase: string }
475
+ | { code: 'already_bound' }
476
+ | { code: 'fingerprint_mismatch'; expected: Contracts.FingerprintFile; got: Contracts.FingerprintFile }
477
+
478
+ /**
479
+ * Diagnostic hooks for observing engine updates.
480
+ */
481
+ export type Hooks<
482
+ M extends Contracts.Intent.Map,
483
+ C extends Contracts.Cursor.Map<M>,
484
+ P extends string,
485
+ R extends Contracts.Result.Base = Contracts.Result.Base,
486
+ > = {
487
+ /** Callback invoked on every state-reducing internal event. */
488
+ onInternalEvent?: (event: Event<M, C, P, R>, state: State<M, C, P, R>) => void
489
+ }
490
+ }
@@ -1,8 +1,3 @@
1
- export * from './commands.types'
2
- export * from './event-map.types'
3
- export * from './internal-events.types'
4
- export * from './outcome.types'
5
- export * from './progress.types'
6
- export * from './reducer'
7
- export * from './store'
8
- export * from './validation'
1
+ export { Engine } from './engine.types'
2
+ export type { Store } from './store'
3
+ export { createUploadStore } from './store'