@contember/react-client 2.0.0-alpha.4 → 2.0.0-alpha.6

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 (74) hide show
  1. package/dist/development/index.cjs +0 -2
  2. package/dist/development/index.cjs.map +1 -1
  3. package/dist/development/index.js +0 -2
  4. package/dist/development/index.js.map +1 -1
  5. package/dist/production/index.cjs +0 -2
  6. package/dist/production/index.cjs.map +1 -1
  7. package/dist/production/index.js +0 -2
  8. package/dist/production/index.js.map +1 -1
  9. package/dist/types/index.d.ts +0 -1
  10. package/dist/types/index.d.ts.map +1 -1
  11. package/dist/types/tsconfig.tsbuildinfo +1 -1
  12. package/package.json +3 -4
  13. package/src/index.ts +0 -1
  14. package/src/tsconfig.json +1 -2
  15. package/dist/development/upload/fileUploadReducer.cjs +0 -149
  16. package/dist/development/upload/fileUploadReducer.cjs.map +0 -1
  17. package/dist/development/upload/fileUploadReducer.js +0 -149
  18. package/dist/development/upload/fileUploadReducer.js.map +0 -1
  19. package/dist/development/upload/toFileId.cjs +0 -10
  20. package/dist/development/upload/toFileId.cjs.map +0 -1
  21. package/dist/development/upload/toFileId.js +0 -10
  22. package/dist/development/upload/toFileId.js.map +0 -1
  23. package/dist/development/upload/useFileUpload.cjs +0 -166
  24. package/dist/development/upload/useFileUpload.cjs.map +0 -1
  25. package/dist/development/upload/useFileUpload.js +0 -166
  26. package/dist/development/upload/useFileUpload.js.map +0 -1
  27. package/dist/production/upload/fileUploadReducer.cjs +0 -149
  28. package/dist/production/upload/fileUploadReducer.cjs.map +0 -1
  29. package/dist/production/upload/fileUploadReducer.js +0 -149
  30. package/dist/production/upload/fileUploadReducer.js.map +0 -1
  31. package/dist/production/upload/toFileId.cjs +0 -10
  32. package/dist/production/upload/toFileId.cjs.map +0 -1
  33. package/dist/production/upload/toFileId.js +0 -10
  34. package/dist/production/upload/toFileId.js.map +0 -1
  35. package/dist/production/upload/useFileUpload.cjs +0 -166
  36. package/dist/production/upload/useFileUpload.cjs.map +0 -1
  37. package/dist/production/upload/useFileUpload.js +0 -166
  38. package/dist/production/upload/useFileUpload.js.map +0 -1
  39. package/dist/types/upload/FileId.d.ts +0 -2
  40. package/dist/types/upload/FileId.d.ts.map +0 -1
  41. package/dist/types/upload/FileUploadAction.d.ts +0 -24
  42. package/dist/types/upload/FileUploadAction.d.ts.map +0 -1
  43. package/dist/types/upload/FileUploadCompoundState.d.ts +0 -4
  44. package/dist/types/upload/FileUploadCompoundState.d.ts.map +0 -1
  45. package/dist/types/upload/FileUploadMetadata.d.ts +0 -6
  46. package/dist/types/upload/FileUploadMetadata.d.ts.map +0 -1
  47. package/dist/types/upload/FileUploadMultiTemporalState.d.ts +0 -7
  48. package/dist/types/upload/FileUploadMultiTemporalState.d.ts.map +0 -1
  49. package/dist/types/upload/FileUploadOperations.d.ts +0 -18
  50. package/dist/types/upload/FileUploadOperations.d.ts.map +0 -1
  51. package/dist/types/upload/FileWithMetadata.d.ts +0 -8
  52. package/dist/types/upload/FileWithMetadata.d.ts.map +0 -1
  53. package/dist/types/upload/SingleFileUploadState.d.ts +0 -35
  54. package/dist/types/upload/SingleFileUploadState.d.ts.map +0 -1
  55. package/dist/types/upload/fileUploadReducer.d.ts +0 -5
  56. package/dist/types/upload/fileUploadReducer.d.ts.map +0 -1
  57. package/dist/types/upload/index.d.ts +0 -8
  58. package/dist/types/upload/index.d.ts.map +0 -1
  59. package/dist/types/upload/toFileId.d.ts +0 -4
  60. package/dist/types/upload/toFileId.d.ts.map +0 -1
  61. package/dist/types/upload/useFileUpload.d.ts +0 -10
  62. package/dist/types/upload/useFileUpload.d.ts.map +0 -1
  63. package/src/upload/FileId.ts +0 -1
  64. package/src/upload/FileUploadAction.ts +0 -30
  65. package/src/upload/FileUploadCompoundState.ts +0 -7
  66. package/src/upload/FileUploadMetadata.ts +0 -6
  67. package/src/upload/FileUploadMultiTemporalState.ts +0 -7
  68. package/src/upload/FileUploadOperations.ts +0 -22
  69. package/src/upload/FileWithMetadata.ts +0 -8
  70. package/src/upload/SingleFileUploadState.ts +0 -43
  71. package/src/upload/fileUploadReducer.ts +0 -166
  72. package/src/upload/index.ts +0 -15
  73. package/src/upload/toFileId.ts +0 -12
  74. package/src/upload/useFileUpload.ts +0 -218
@@ -1,166 +0,0 @@
1
- import { FileUploadError } from '@contember/client'
2
- import { assertNever } from '@contember/utilities'
3
- import type { FileId } from './FileId'
4
- import type { FileUploadAction } from './FileUploadAction'
5
- import type { FileUploadMultiTemporalState } from './FileUploadMultiTemporalState'
6
- import { toFileId } from './toFileId'
7
-
8
- export const initializeFileUploadState = <Result = unknown, Metadata = undefined>(): FileUploadMultiTemporalState<Result, Metadata> => ({
9
- fileIdByFile: new WeakMap<File, FileId>(),
10
- state: new Map(),
11
- })
12
-
13
- export const fileUploadReducer = <Result = unknown, Metadata = undefined>(
14
- previousState: FileUploadMultiTemporalState<Result, Metadata>,
15
- action: FileUploadAction<Result, Metadata>,
16
- ): FileUploadMultiTemporalState<Result, Metadata> => {
17
- let newState: undefined | FileUploadMultiTemporalState<Result, Metadata>['state'] = undefined
18
-
19
- switch (action.type) {
20
- case 'initialize': {
21
- for (const [fileId, metadata] of action.files) {
22
- // Deliberately allowing starting a new upload with the same id
23
- (newState ??= new Map(previousState.state)).set(fileId, {
24
- readyState: 'initializing',
25
- abortController: metadata.abortController,
26
- previewUrl: metadata.previewUrl,
27
- file: metadata.file,
28
- })
29
- // Deliberately mutating
30
- previousState.fileIdByFile.set(metadata.file, fileId)
31
- }
32
- break
33
- }
34
- case 'startUploading': {
35
- for (const [fileOrId, metadata] of action.files) {
36
- const fileId = toFileId(previousState, fileOrId)
37
- const fileState = (newState ?? previousState.state).get(fileId)
38
-
39
- if (fileState === undefined || fileState.readyState !== 'initializing') {
40
- continue
41
- }
42
-
43
- (newState ??= new Map(previousState.state)).set(fileId, {
44
- readyState: 'uploading',
45
- abortController: fileState.abortController,
46
- file: fileState.file,
47
- metadata: metadata.metadata!, // If the user didn't supply the metadata, then that's on them.
48
- previewUrl: fileState.previewUrl,
49
- progress: undefined,
50
- uploader: metadata.uploader,
51
- })
52
- }
53
- break
54
- }
55
- case 'finishSuccessfully': {
56
- for (const [fileOrId, result] of action.result) {
57
- const fileId = toFileId(previousState, fileOrId)
58
- const previousFileState = (newState ?? previousState.state).get(fileId)
59
- if (previousFileState === undefined || previousFileState.readyState !== 'uploading') {
60
- continue
61
- }
62
- (newState ??= new Map(previousState.state)).set(fileId, {
63
- readyState: 'success',
64
- file: previousFileState.file,
65
- metadata: previousFileState.metadata,
66
- previewUrl: previousFileState.previewUrl,
67
- result,
68
- uploader: previousFileState.uploader,
69
- })
70
- }
71
- break
72
- }
73
- case 'finishWithError': {
74
- for (const errorSpec of action.error) {
75
- let fileOrId: File | FileId
76
- let rawError: unknown
77
-
78
- if (Array.isArray(errorSpec)) {
79
- [fileOrId, rawError] = errorSpec
80
- } else {
81
- fileOrId = errorSpec
82
- rawError = undefined
83
- }
84
-
85
- const errors: FileUploadError[] = []
86
-
87
- if (rawError instanceof FileUploadError) {
88
- errors.push(rawError)
89
- } else if (Array.isArray(rawError)) {
90
- for (const error of rawError) {
91
- if (error instanceof FileUploadError) {
92
- errors.push(error)
93
- }
94
- }
95
- }
96
-
97
- const fileId = toFileId(previousState, fileOrId)
98
- const previousFileState = (newState ?? previousState.state).get(fileId)
99
- if (
100
- previousFileState === undefined ||
101
- (previousFileState.readyState !== 'initializing' && previousFileState.readyState !== 'uploading')
102
- ) {
103
- continue
104
- }
105
- const uploader = previousFileState.readyState === 'uploading' ? previousFileState.uploader : undefined
106
- const metadata = previousFileState.readyState === 'uploading' ? previousFileState.metadata : undefined
107
- ; (newState ??= new Map(previousState.state)).set(fileId, {
108
- readyState: 'error',
109
- errors: errors.length ? errors : undefined,
110
- rawError,
111
- file: previousFileState.file,
112
- metadata,
113
- previewUrl: previousFileState.previewUrl,
114
- uploader,
115
- })
116
- }
117
- break
118
- }
119
- case 'purge': {
120
- for (const fileOrId of action.files) {
121
- const fileId = toFileId(previousState, fileOrId)
122
- const fileState = (newState ?? previousState.state).get(fileId)
123
-
124
- if (fileState === undefined) {
125
- continue
126
- }
127
- URL.revokeObjectURL(fileState.previewUrl)
128
- if (fileState.readyState === 'initializing' || fileState.readyState === 'uploading') {
129
- fileState.abortController.abort() // This is a bit naughty… We shouldn't do this from here.
130
- }
131
- (newState ??= new Map(previousState.state)).delete(fileId)
132
- }
133
- break
134
- }
135
- case 'updateUploadProgress': {
136
- for (const [fileOrId, { progress }] of action.progress) {
137
- const fileId = toFileId(previousState, fileOrId)
138
- const previousFileState = (newState ?? previousState.state).get(fileId)
139
- if (progress === undefined || previousFileState === undefined || previousFileState.readyState !== 'uploading') {
140
- continue
141
- }
142
-
143
- if (previousFileState.progress && Math.abs(progress - previousFileState.progress) < 0.01) {
144
- continue
145
- }
146
-
147
- (newState ??= new Map(previousState.state)).set(fileId, {
148
- readyState: 'uploading',
149
- file: previousFileState.file,
150
- uploader: previousFileState.uploader,
151
- abortController: previousFileState.abortController,
152
- previewUrl: previousFileState.previewUrl,
153
- metadata: previousFileState.metadata,
154
- progress: progress,
155
- })
156
- }
157
- break
158
- }
159
- default:
160
- assertNever(action)
161
- }
162
- if (newState === undefined) {
163
- return previousState
164
- }
165
- return { ...previousState, state: newState }
166
- }
@@ -1,15 +0,0 @@
1
- export * from './useFileUpload'
2
-
3
- export type { FileId } from './FileId'
4
- export type { FileUploadCompoundState } from './FileUploadCompoundState'
5
- export type { FileUploadMetadata } from './FileUploadMetadata'
6
- export type {
7
- StartUploadFileOptions,
8
- StartUpload,
9
- FileUploadOperations,
10
- InitializeUpload,
11
- PurgeUpload,
12
- FailUpload,
13
- } from './FileUploadOperations'
14
- export type { FileWithMetadata } from './FileWithMetadata'
15
- export * from './SingleFileUploadState'
@@ -1,12 +0,0 @@
1
- import type { FileId } from './FileId'
2
- import type { FileUploadMultiTemporalState } from './FileUploadMultiTemporalState'
3
-
4
- export const toFileId = <Result = unknown, Metadata = undefined>(
5
- state: FileUploadMultiTemporalState<Result, Metadata>,
6
- fileOrId: File | FileId,
7
- ): FileId => {
8
- if (fileOrId instanceof File) {
9
- return state.fileIdByFile.get(fileOrId)! // Should we throw instead of the yolo "!"?
10
- }
11
- return fileOrId
12
- }
@@ -1,218 +0,0 @@
1
- import { FileUploader, S3FileUploader, UploadedFileMetadata } from '@contember/client'
2
- import { Reducer, useCallback, useEffect, useMemo, useReducer, useRef } from 'react'
3
- import { useCurrentContentGraphQlClient } from '../content'
4
- import type { FileId } from './FileId'
5
- import type { FileUploadAction } from './FileUploadAction'
6
- import type { FileUploadCompoundState } from './FileUploadCompoundState'
7
- import type { FileUploadMetadata } from './FileUploadMetadata'
8
- import type { FileUploadMultiTemporalState } from './FileUploadMultiTemporalState'
9
- import type {
10
- PurgeUpload,
11
- FileUploadOperations,
12
- InitializeUpload,
13
- StartUpload,
14
- StartUploadFileOptions,
15
- FailUpload,
16
- } from './FileUploadOperations'
17
- import { fileUploadReducer, initializeFileUploadState } from './fileUploadReducer'
18
- import type { FileWithMetadata } from './FileWithMetadata'
19
-
20
- export type FileUpload<Result = unknown, Metadata = undefined> = [
21
- FileUploadCompoundState<Result, Metadata>,
22
- FileUploadOperations<Metadata>,
23
- ]
24
-
25
- export interface FileUploadOptions {
26
- }
27
-
28
- export const useFileUpload = <Result = unknown, Metadata = undefined>({}: FileUploadOptions = {}): FileUpload<Result, Metadata> => {
29
- const contentApiClient = useCurrentContentGraphQlClient()
30
-
31
- const fileIdSeedRef = useRef(1)
32
-
33
- const [internalState, dispatch] = useReducer<
34
- Reducer<FileUploadMultiTemporalState<Result, Metadata>, FileUploadAction<Result, Metadata>>,
35
- undefined
36
- >(fileUploadReducer, undefined, initializeFileUploadState)
37
-
38
- const defaultUploader = useMemo(() => new S3FileUploader(), [])
39
-
40
- const purgeUpload = useCallback<PurgeUpload>(files => {
41
- dispatch({
42
- type: 'purge',
43
- files,
44
- })
45
- }, [])
46
- const failUpload = useCallback<FailUpload>(error => {
47
- dispatch({
48
- type: 'finishWithError',
49
- error,
50
- })
51
- }, [])
52
-
53
- const previewUrls = useRef(new Set<string>())
54
- const fileIds = useRef(new WeakMap<File, FileId>())
55
- const filesWithMetadataById = useRef(new Map<FileId, WeakRef<FileWithMetadata>>)
56
-
57
- const initializeUpload = useCallback<InitializeUpload>(
58
- files => {
59
- const newFileIds = new Set<FileId>()
60
- const fileWithMetadataByFileConfig = new Map<FileId, FileWithMetadata>()
61
-
62
- for (const fileMaybeWithId of files) {
63
- const abortController = new AbortController()
64
-
65
- let fileId: FileId
66
- let file: File
67
-
68
- if (fileMaybeWithId instanceof File) {
69
- fileId = `__contember__file-${fileIdSeedRef.current++}`
70
- file = fileMaybeWithId
71
- } else {
72
- fileId = fileMaybeWithId[0]
73
- file = fileMaybeWithId[1]
74
- }
75
-
76
- abortController.signal.addEventListener('abort', () => {
77
- purgeUpload([fileId])
78
- })
79
-
80
- const previewUrl = URL.createObjectURL(file)
81
- const fileWithMetadata: FileWithMetadata = {
82
- previewUrl: previewUrl,
83
- abortController,
84
- file,
85
- fileId,
86
- }
87
- fileWithMetadataByFileConfig.set(fileId, fileWithMetadata)
88
-
89
- newFileIds.add(fileId)
90
-
91
- previewUrls.current.add(previewUrl)
92
- fileIds.current.set(file, fileId)
93
- filesWithMetadataById.current.set(fileId, new WeakRef(fileWithMetadata))
94
- }
95
- if (fileWithMetadataByFileConfig.size === 0) {
96
- return fileWithMetadataByFileConfig
97
- }
98
-
99
- if (newFileIds.size) {
100
- dispatch({
101
- type: 'purge',
102
- files: newFileIds,
103
- })
104
- }
105
-
106
- dispatch({
107
- type: 'initialize',
108
- files: fileWithMetadataByFileConfig,
109
- })
110
-
111
- return fileWithMetadataByFileConfig
112
- },
113
- [purgeUpload],
114
- )
115
- const startUpload = useCallback<StartUpload<Metadata>>(
116
- files => {
117
- const filesById = new Map<FileId, FileUploadMetadata<Metadata>>()
118
- const groupedByUploader: Map<FileUploader, Map<File, UploadedFileMetadata>> = new Map()
119
-
120
- for (const fileOrIdMaybeWithOptions of files) {
121
- let fileOrId: File | FileId
122
- let options: StartUploadFileOptions<Metadata>
123
-
124
- if (Array.isArray(fileOrIdMaybeWithOptions)) {
125
- fileOrId = fileOrIdMaybeWithOptions[0]
126
- options = fileOrIdMaybeWithOptions[1]
127
- } else {
128
- fileOrId = fileOrIdMaybeWithOptions
129
- options = {}
130
- }
131
- const { uploader = defaultUploader, metadata } = options
132
-
133
- const fileId = fileOrId instanceof File ? fileIds.current.get(fileOrId) : fileOrId
134
- const fileState = fileId ? filesWithMetadataById.current.get(fileId)?.deref() : undefined
135
-
136
- if (fileId === undefined || fileState === undefined) {
137
- throw new Error(
138
- `Trying to startUpload a file that hasn't been previously initialized. ` +
139
- `This will be possible in future, but isn't yet.`,
140
- )
141
- }
142
-
143
-
144
- filesById.set(fileId, {
145
- uploader,
146
- metadata,
147
- })
148
-
149
- let filesWithSameUploader = groupedByUploader.get(uploader)
150
- if (filesWithSameUploader === undefined) {
151
- groupedByUploader.set(uploader, (filesWithSameUploader = new Map()))
152
- }
153
- filesWithSameUploader.set(fileState.file, {
154
- abortSignal: fileState.abortController.signal,
155
- })
156
- }
157
-
158
- dispatch({
159
- type: 'startUploading',
160
- files: filesById,
161
- })
162
-
163
- for (const [uploader, filesForUpload] of groupedByUploader) {
164
- try {
165
- uploader.upload(filesForUpload, {
166
- onProgress: progress => {
167
- dispatch({
168
- type: 'updateUploadProgress',
169
- progress,
170
- })
171
- },
172
- onSuccess: result => {
173
- dispatch({
174
- type: 'finishSuccessfully',
175
- result,
176
- })
177
- },
178
- onError: error => {
179
- dispatch({
180
- type: 'finishWithError',
181
- error,
182
- })
183
- },
184
- contentApiClient,
185
- })
186
- } catch (error) {
187
- dispatch({
188
- type: 'finishWithError',
189
- error: Array.from(filesForUpload).map(([file]) => [file, error]),
190
- })
191
- }
192
- }
193
- },
194
- [contentApiClient, defaultUploader],
195
- )
196
-
197
- const operations = useMemo<FileUploadOperations<Metadata>>(
198
- () => ({
199
- failUpload,
200
- initializeUpload,
201
- purgeUpload,
202
- startUpload,
203
- }),
204
- [failUpload, initializeUpload, purgeUpload, startUpload],
205
- )
206
-
207
-
208
- useEffect(
209
- () => () => {
210
- for (const previewUrl of Array.from(previewUrls.current)) {
211
- URL.revokeObjectURL(previewUrl)
212
- }
213
- },
214
- [],
215
- )
216
-
217
- return [internalState.state, operations]
218
- }