@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
@@ -1,45 +0,0 @@
1
- import type {
2
- AnyCursor,
3
- CursorMap,
4
- FileFingerprint,
5
- IntentMap,
6
- RejectReason,
7
- UploadError,
8
- UploadResultBase,
9
- } from '../contracts'
10
- import type { UploadCompletionKind } from './outcome.types'
11
-
12
- /**
13
- * Public event map emitted to consumers.
14
- *
15
- * Consumers subscribe via {@link TypedEmitter.on}.
16
- */
17
- export type UploadEventMap<
18
- M extends IntentMap,
19
- C extends CursorMap<M>,
20
- P extends string,
21
- R extends UploadResultBase = UploadResultBase,
22
- > = {
23
- 'file.added': { localId: string; purpose: P; file: File; fingerprint: FileFingerprint }
24
- 'file.rejected': { file: File; reason: RejectReason }
25
-
26
- 'validation.ok': { localId: string }
27
- 'validation.failed': { localId: string; reason: RejectReason }
28
-
29
- 'intent.creating': { localId: string }
30
- 'intent.created': { localId: string; intent: M[keyof M] }
31
- 'intent.failed': { localId: string; error: UploadError; retryable: boolean }
32
-
33
- 'upload.queued': { localId: string }
34
- 'upload.resumed': { localId: string }
35
- 'upload.started': { localId: string }
36
- 'upload.progress': { localId: string; pct: number; uploadedBytes: number; totalBytes: number }
37
- 'upload.cursor': { localId: string; cursor: AnyCursor<C> }
38
- 'upload.paused': { localId: string; cursor: AnyCursor<C> }
39
- 'upload.canceled': { localId: string }
40
-
41
- 'upload.completing': { localId: string }
42
- 'upload.completed': { localId: string; result: R; completedBy: UploadCompletionKind }
43
-
44
- 'upload.error': { localId: string; error: UploadError; retryable: boolean }
45
- }
@@ -1,222 +0,0 @@
1
- import type {
2
- AnyCursor,
3
- AnyIntent,
4
- CursorMap,
5
- FileFingerprint,
6
- IntentMap,
7
- RejectReason,
8
- UploadError,
9
- UploadResultBase,
10
- } from '../contracts'
11
- import type { UploadCompletionKind } from './outcome.types'
12
- import type { UploadProgress } from './progress.types'
13
-
14
- /**
15
- * Internal events emitted by effects and consumed by the reducer.
16
- *
17
- * These are not the same as public events. They are designed for correctness and state transitions.
18
- *
19
- * @typeParam M - Intent map
20
- * @typeParam C - Cursor map
21
- */
22
- export type InternalEvent<
23
- M extends IntentMap,
24
- C extends CursorMap<M>,
25
- P extends string,
26
- R extends UploadResultBase = UploadResultBase,
27
- > =
28
- | {
29
- type: 'files.added'
30
- items: Array<{ localId: string; purpose: P; file: File; fingerprint: FileFingerprint; createdAt: number }>
31
- }
32
- | { type: 'fingerprint.updated'; localId: string; fingerprint: FileFingerprint }
33
- | { type: 'validation.ok'; localId: string }
34
- | { type: 'validation.failed'; localId: string; reason: RejectReason }
35
- | { type: 'intent.ok'; localId: string; intent: AnyIntent<M> }
36
- | { type: 'intent.failed'; localId: string; error: UploadError; retryable: boolean }
37
- | { type: 'upload.begin'; localId: string; startedAt: number }
38
- | { type: 'upload.progress'; localId: string; uploadedBytes: number; totalBytes: number }
39
- | { type: 'cursor.updated'; localId: string; cursor: AnyCursor<C> }
40
- | { type: 'upload.ok'; localId: string }
41
- | { type: 'upload.failed'; localId: string; error: UploadError; retryable: boolean }
42
- | { type: 'dedupe.ok'; localId: string; result: R }
43
- | { type: 'complete.ok'; localId: string; result: R }
44
- | { type: 'complete.failed'; localId: string; error: UploadError; retryable: boolean }
45
- /** Internal completion for pause requests. */
46
- | { type: 'paused'; localId: string; cursor: AnyCursor<C>; pausedAt: number }
47
- /** Internal completion for cancel requests. */
48
- | { type: 'canceled'; localId: string; canceledAt: number }
49
-
50
- // ============================================================================
51
- // UPLOAD ITEM (STATE MACHINE)
52
- // ============================================================================
53
-
54
- /**
55
- * All possible upload phases.
56
- *
57
- * Useful for constraints and UI filtering.
58
- */
59
- export type UploadPhase =
60
- | 'validating'
61
- | 'creating_intent'
62
- | 'ready'
63
- | 'queued'
64
- | 'uploading'
65
- | 'paused'
66
- | 'completing'
67
- | 'completed'
68
- | 'error'
69
- | 'canceled'
70
-
71
- /**
72
- * State of a single upload item.
73
- *
74
- * This is a discriminated union on `phase`.
75
- *
76
- * @typeParam M - Intent map
77
- * @typeParam C - Cursor map
78
- * @typeParam P - Purpose union
79
- */
80
- export type UploadItem<
81
- M extends IntentMap,
82
- C extends CursorMap<M>,
83
- P extends string,
84
- R extends UploadResultBase = UploadResultBase,
85
- > =
86
- | {
87
- /** Validating file against rules. */
88
- phase: 'validating'
89
- localId: string
90
- purpose: P
91
- fingerprint: FileFingerprint
92
- file: File
93
- createdAt: number
94
- }
95
- | {
96
- /** Requesting upload intent from backend. */
97
- phase: 'creating_intent'
98
- localId: string
99
- purpose: P
100
- fingerprint: FileFingerprint
101
- file: File
102
- /** Current attempt number for this phase. */
103
- attempt: number
104
- createdAt: number
105
- }
106
- | {
107
- /** Intent received, ready to start upload. */
108
- phase: 'ready'
109
- localId: string
110
- purpose: P
111
- fingerprint: FileFingerprint
112
- file: File
113
- intent: AnyIntent<M>
114
- createdAt: number
115
- cursor?: AnyCursor<C>
116
- progress?: UploadProgress
117
- attempt?: number
118
- }
119
- | {
120
- /** Queued for upload (waiting for slot). */
121
- phase: 'queued'
122
- localId: string
123
- purpose: P
124
- fingerprint: FileFingerprint
125
- file: File
126
- intent: AnyIntent<M>
127
- /** Timestamp when this item requested a concurrency slot. */
128
- requestedAt: number
129
- createdAt: number
130
- cursor?: AnyCursor<C>
131
- progress?: UploadProgress
132
- attempt?: number
133
- }
134
- | {
135
- /** Actively uploading bytes. */
136
- phase: 'uploading'
137
- localId: string
138
- purpose: P
139
- fingerprint: FileFingerprint
140
- file: File
141
- intent: AnyIntent<M>
142
- startedAt: number
143
- progress: UploadProgress
144
- createdAt: number
145
- cursor?: AnyCursor<C>
146
- attempt?: number
147
- }
148
- | {
149
- /** Upload paused (resumable). */
150
- phase: 'paused'
151
- localId: string
152
- purpose: P
153
- fingerprint: FileFingerprint
154
- intent: AnyIntent<M>
155
- cursor: AnyCursor<C>
156
- progress: UploadProgress
157
- pausedAt: number
158
- createdAt: number
159
- /**
160
- * File is optional because a paused item can be restored from persistence without a File.
161
- * Use `rebind` to attach the File again before resuming (when required).
162
- */
163
- file?: File
164
- attempt?: number
165
- }
166
- | {
167
- /** Bytes sent, finalizing with backend. */
168
- phase: 'completing'
169
- localId: string
170
- purpose: P
171
- fingerprint: FileFingerprint
172
- file: File
173
- intent: AnyIntent<M>
174
- progress: UploadProgress
175
- completingAt: number
176
- createdAt: number
177
- attempt?: number
178
- }
179
- | {
180
- /** Upload completed successfully. */
181
- phase: 'completed'
182
- localId: string
183
- file: File
184
- purpose: P
185
- fingerprint: FileFingerprint
186
- intent?: AnyIntent<M>
187
- completedBy: UploadCompletionKind
188
- result: R
189
- completedAt: number
190
- createdAt: number
191
- attempt?: number
192
- }
193
- | {
194
- /** Upload failed (retryable or final). */
195
- phase: 'error'
196
- localId: string
197
- purpose: P
198
- fingerprint: FileFingerprint
199
- error: UploadError
200
- retryable: boolean
201
- attempt: number
202
- failedAt: number
203
- createdAt: number
204
- file?: File
205
- intent?: AnyIntent<M>
206
- cursor?: AnyCursor<C>
207
- progress?: UploadProgress
208
- }
209
- | {
210
- /** Upload canceled by user/system. */
211
- phase: 'canceled'
212
- localId: string
213
- purpose: P
214
- fingerprint: FileFingerprint
215
- canceledAt: number
216
- createdAt: number
217
- file?: File
218
- intent?: AnyIntent<M>
219
- cursor?: AnyCursor<C>
220
- progress?: UploadProgress
221
- attempt?: number
222
- }
@@ -1,9 +0,0 @@
1
- import type { UploadError, UploadResultBase } from '../contracts'
2
-
3
- export type UploadCompletionKind = 'upload' | 'dedupe'
4
-
5
- export type UploadOutcome<R extends UploadResultBase> =
6
- | { localId: string; status: 'completed'; completedBy: UploadCompletionKind; result: R }
7
- | { localId: string; status: 'error'; error: UploadError }
8
- | { localId: string; status: 'canceled' }
9
- | { localId: string; status: 'missing' }
@@ -1,15 +0,0 @@
1
- /**
2
- * Upload progress snapshot.
3
- *
4
- * Invariants:
5
- * - `totalBytes` should be `file.size` when known.
6
- * - `pct` should be clamped to 0..100.
7
- */
8
- export type UploadProgress = {
9
- /** Bytes uploaded so far. */
10
- uploadedBytes: number
11
- /** Total bytes to upload. */
12
- totalBytes: number
13
- /** Percent complete (0..100). */
14
- pct: number
15
- }