@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
|
@@ -22,7 +22,12 @@ export function serializeSnapshot<
|
|
|
22
22
|
if (!hasIntent(item)) continue
|
|
23
23
|
|
|
24
24
|
// Do not persist terminal items. Persistence is for resuming and recovery, not history.
|
|
25
|
-
if (
|
|
25
|
+
if (
|
|
26
|
+
(item.phase as string) === 'completed' ||
|
|
27
|
+
(item.phase as string) === 'canceled' ||
|
|
28
|
+
(item.phase as string) === 'error'
|
|
29
|
+
)
|
|
30
|
+
continue
|
|
26
31
|
|
|
27
32
|
const cursor = hasCursor(item) ? item.cursor : undefined
|
|
28
33
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { TypedEmitter } from './emitter.types'
|
|
2
|
+
|
|
2
3
|
export type { TypedEmitter } from './emitter.types'
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -29,7 +30,11 @@ export function createTypedEmitter<E extends Record<string, unknown>>(): TypedEm
|
|
|
29
30
|
return {
|
|
30
31
|
on<K extends keyof E & string>(type: K, cb: (payload: E[K]) => void): () => void {
|
|
31
32
|
// Create listener set for this event type if it doesn't exist
|
|
32
|
-
|
|
33
|
+
let set = listeners[type]
|
|
34
|
+
if (!set) {
|
|
35
|
+
set = new Set<(payload: E[K]) => void>()
|
|
36
|
+
listeners[type] = set
|
|
37
|
+
}
|
|
33
38
|
set.add(cb)
|
|
34
39
|
|
|
35
40
|
// Return unsubscribe function
|
|
@@ -52,6 +52,31 @@ export function UploadProvider<
|
|
|
52
52
|
return <UploadContext.Provider value={store}>{children}</UploadContext.Provider>
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Hook to access the upload store from React context when present.
|
|
57
|
+
*
|
|
58
|
+
* Some higher-level hooks support either an explicit store argument or context.
|
|
59
|
+
* They use this helper so the context read stays unconditional without throwing
|
|
60
|
+
* when a caller intentionally passes a store instance.
|
|
61
|
+
*/
|
|
62
|
+
export function useOptionalUploadStore<
|
|
63
|
+
M extends IntentMap,
|
|
64
|
+
C extends CursorMap<M>,
|
|
65
|
+
P extends string,
|
|
66
|
+
R extends UploadResultBase = UploadResultBase,
|
|
67
|
+
>(): UploadStore<M, C, P, R> | null {
|
|
68
|
+
const store = useContext(UploadContext)
|
|
69
|
+
if (store === null) {
|
|
70
|
+
return null
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!isUploadStore<M, C, P, R>(store)) {
|
|
74
|
+
throw new Error('UploadProvider received an invalid store value')
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return store
|
|
78
|
+
}
|
|
79
|
+
|
|
55
80
|
/**
|
|
56
81
|
* Hook to access the upload store from React context.
|
|
57
82
|
*
|
|
@@ -74,8 +99,8 @@ export function useUploadStore<
|
|
|
74
99
|
P extends string,
|
|
75
100
|
R extends UploadResultBase = UploadResultBase,
|
|
76
101
|
>(): UploadStore<M, C, P, R> {
|
|
77
|
-
const store =
|
|
78
|
-
if (!store
|
|
102
|
+
const store = useOptionalUploadStore<M, C, P, R>()
|
|
103
|
+
if (!store) {
|
|
79
104
|
throw new Error('useUploadStore must be used within UploadProvider')
|
|
80
105
|
}
|
|
81
106
|
return store
|
|
@@ -11,7 +11,7 @@ import type {
|
|
|
11
11
|
UploadResultBase,
|
|
12
12
|
} from '../core'
|
|
13
13
|
import type { UploadStore } from '../core/engine/store'
|
|
14
|
-
import { useUploadStore } from './upload-provider'
|
|
14
|
+
import { useOptionalUploadStore, useUploadStore } from './upload-provider'
|
|
15
15
|
|
|
16
16
|
export function createUploadFactory<
|
|
17
17
|
M extends IntentMap,
|
|
@@ -46,6 +46,22 @@ type Uploader<M extends IntentMap, C extends CursorMap<M>, P extends string, R e
|
|
|
46
46
|
ready: UploadItem<M, C, P, R>[]
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Stable action surface for React consumers that need imperative store access.
|
|
51
|
+
*
|
|
52
|
+
* This is declared explicitly instead of relying on an inferred object return
|
|
53
|
+
* type so the generated package declarations do not leak the internal generic
|
|
54
|
+
* names created by `store.on.bind(store)`.
|
|
55
|
+
*/
|
|
56
|
+
export type UploaderActions<
|
|
57
|
+
M extends IntentMap,
|
|
58
|
+
C extends CursorMap<M>,
|
|
59
|
+
P extends string,
|
|
60
|
+
R extends UploadResultBase = UploadResultBase,
|
|
61
|
+
> = Pick<UploadStore<M, C, P, R>, 'dispatch' | 'on'> & {
|
|
62
|
+
store: UploadStore<M, C, P, R>
|
|
63
|
+
}
|
|
64
|
+
|
|
49
65
|
export function useUploader<
|
|
50
66
|
M extends IntentMap,
|
|
51
67
|
C extends CursorMap<M>,
|
|
@@ -63,8 +79,13 @@ export function useUploader<
|
|
|
63
79
|
C extends CursorMap<M>,
|
|
64
80
|
P extends string,
|
|
65
81
|
R extends UploadResultBase = UploadResultBase,
|
|
66
|
-
>(
|
|
67
|
-
const
|
|
82
|
+
>(providedStore?: UploadStore<M, C, P, R> | undefined) {
|
|
83
|
+
const contextStore = useOptionalUploadStore<M, C, P, R>()
|
|
84
|
+
const store = providedStore ?? contextStore
|
|
85
|
+
if (!store) {
|
|
86
|
+
throw new Error('useUploader must be used within UploadProvider when no store argument is provided')
|
|
87
|
+
}
|
|
88
|
+
|
|
68
89
|
const snapshot = React.useSyncExternalStore(
|
|
69
90
|
store.subscribe.bind(store),
|
|
70
91
|
store.getSnapshot.bind(store),
|
|
@@ -105,7 +126,7 @@ export function useUploaderActions<
|
|
|
105
126
|
C extends CursorMap<M>,
|
|
106
127
|
P extends string,
|
|
107
128
|
R extends UploadResultBase = UploadResultBase,
|
|
108
|
-
>() {
|
|
129
|
+
>(): UploaderActions<M, C, P, R> {
|
|
109
130
|
const store = useUploadStore<M, C, P, R>()
|
|
110
131
|
|
|
111
132
|
const dispatch = React.useMemo(() => store.dispatch.bind(store), [store])
|
|
@@ -160,7 +160,7 @@ export function multipartStrategy<
|
|
|
160
160
|
.map(([partNumber, v]) => ({ partNumber, etag: v.etag, size: v.size }))
|
|
161
161
|
.sort((a, b) => a.partNumber - b.partNumber),
|
|
162
162
|
}
|
|
163
|
-
ctx.persistCursor(snapshot as C[
|
|
163
|
+
ctx.persistCursor(snapshot as C['multipart'])
|
|
164
164
|
report()
|
|
165
165
|
} catch (err) {
|
|
166
166
|
inflightBytes.delete(p.partNumber)
|
|
@@ -236,7 +236,7 @@ export function multipartStrategy<
|
|
|
236
236
|
.sort((a, b) => a.partNumber - b.partNumber),
|
|
237
237
|
completed: true,
|
|
238
238
|
}
|
|
239
|
-
ctx.persistCursor(snapshot as C[
|
|
239
|
+
ctx.persistCursor(snapshot as C['multipart'])
|
|
240
240
|
}
|
|
241
241
|
},
|
|
242
242
|
}
|