@wordpress/media-utils 5.6.0 → 5.8.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 (100) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +70 -1
  3. package/build/index.js +43 -11
  4. package/build/index.js.map +1 -1
  5. package/build/utils/flatten-form-data.js +32 -0
  6. package/build/utils/flatten-form-data.js.map +1 -0
  7. package/build/utils/get-mime-types-array.js +27 -0
  8. package/build/utils/get-mime-types-array.js.map +1 -0
  9. package/build/utils/transform-attachment.js +33 -0
  10. package/build/utils/transform-attachment.js.map +1 -0
  11. package/build/utils/types.js +6 -0
  12. package/build/utils/types.js.map +1 -0
  13. package/build/utils/upload-error.js +29 -0
  14. package/build/utils/upload-error.js.map +1 -0
  15. package/build/utils/upload-media.js +53 -152
  16. package/build/utils/upload-media.js.map +1 -1
  17. package/build/utils/upload-to-server.js +34 -0
  18. package/build/utils/upload-to-server.js.map +1 -0
  19. package/build/utils/validate-file-size.js +44 -0
  20. package/build/utils/validate-file-size.js.map +1 -0
  21. package/build/utils/validate-mime-type-for-user.js +41 -0
  22. package/build/utils/validate-mime-type-for-user.js.map +1 -0
  23. package/build/utils/validate-mime-type.js +47 -0
  24. package/build/utils/validate-mime-type.js.map +1 -0
  25. package/build-module/index.js +5 -1
  26. package/build-module/index.js.map +1 -1
  27. package/build-module/utils/flatten-form-data.js +26 -0
  28. package/build-module/utils/flatten-form-data.js.map +1 -0
  29. package/build-module/utils/get-mime-types-array.js +21 -0
  30. package/build-module/utils/get-mime-types-array.js.map +1 -0
  31. package/build-module/utils/transform-attachment.js +27 -0
  32. package/build-module/utils/transform-attachment.js.map +1 -0
  33. package/build-module/utils/types.js +2 -0
  34. package/build-module/utils/types.js.map +1 -0
  35. package/build-module/utils/upload-error.js +22 -0
  36. package/build-module/utils/upload-error.js.map +1 -0
  37. package/build-module/utils/upload-media.js +53 -149
  38. package/build-module/utils/upload-media.js.map +1 -1
  39. package/build-module/utils/upload-to-server.js +26 -0
  40. package/build-module/utils/upload-to-server.js.map +1 -0
  41. package/build-module/utils/validate-file-size.js +38 -0
  42. package/build-module/utils/validate-file-size.js.map +1 -0
  43. package/build-module/utils/validate-mime-type-for-user.js +35 -0
  44. package/build-module/utils/validate-mime-type-for-user.js.map +1 -0
  45. package/build-module/utils/validate-mime-type.js +41 -0
  46. package/build-module/utils/validate-mime-type.js.map +1 -0
  47. package/build-types/components/index.d.ts +2 -0
  48. package/build-types/components/index.d.ts.map +1 -0
  49. package/build-types/components/media-upload/index.d.ts +30 -0
  50. package/build-types/components/media-upload/index.d.ts.map +1 -0
  51. package/build-types/index.d.ts +8 -0
  52. package/build-types/index.d.ts.map +1 -0
  53. package/build-types/utils/flatten-form-data.d.ts +9 -0
  54. package/build-types/utils/flatten-form-data.d.ts.map +1 -0
  55. package/build-types/utils/get-mime-types-array.d.ts +12 -0
  56. package/build-types/utils/get-mime-types-array.d.ts.map +1 -0
  57. package/build-types/utils/transform-attachment.d.ts +11 -0
  58. package/build-types/utils/transform-attachment.d.ts.map +1 -0
  59. package/build-types/utils/types.d.ts +199 -0
  60. package/build-types/utils/types.d.ts.map +1 -0
  61. package/build-types/utils/upload-error.d.ts +19 -0
  62. package/build-types/utils/upload-error.d.ts.map +1 -0
  63. package/build-types/utils/upload-media.d.ts +32 -0
  64. package/build-types/utils/upload-media.d.ts.map +1 -0
  65. package/build-types/utils/upload-to-server.d.ts +3 -0
  66. package/build-types/utils/upload-to-server.d.ts.map +1 -0
  67. package/build-types/utils/validate-file-size.d.ts +8 -0
  68. package/build-types/utils/validate-file-size.d.ts.map +1 -0
  69. package/build-types/utils/validate-mime-type-for-user.d.ts +8 -0
  70. package/build-types/utils/validate-mime-type-for-user.d.ts.map +1 -0
  71. package/build-types/utils/validate-mime-type.d.ts +8 -0
  72. package/build-types/utils/validate-mime-type.d.ts.map +1 -0
  73. package/package.json +8 -7
  74. package/src/index.ts +9 -0
  75. package/src/utils/flatten-form-data.ts +33 -0
  76. package/src/utils/get-mime-types-array.ts +29 -0
  77. package/src/utils/test/flatten-form-data.ts +49 -0
  78. package/src/utils/test/get-mime-types-array.ts +47 -0
  79. package/src/utils/test/upload-error.ts +24 -0
  80. package/src/utils/test/{upload-media.test.js → upload-media.ts} +47 -76
  81. package/src/utils/test/validate-file-size.ts +70 -0
  82. package/src/utils/test/validate-mime-type-for-user.ts +37 -0
  83. package/src/utils/test/validate-mime-type.ts +57 -0
  84. package/src/utils/transform-attachment.ts +24 -0
  85. package/src/utils/types.ts +207 -0
  86. package/src/utils/upload-error.ts +26 -0
  87. package/src/utils/upload-media.ts +149 -0
  88. package/src/utils/upload-to-server.ts +38 -0
  89. package/src/utils/validate-file-size.ts +44 -0
  90. package/src/utils/validate-mime-type-for-user.ts +46 -0
  91. package/src/utils/validate-mime-type.ts +43 -0
  92. package/tsconfig.json +17 -0
  93. package/tsconfig.tsbuildinfo +1 -0
  94. package/build/utils/index.js +0 -13
  95. package/build/utils/index.js.map +0 -1
  96. package/build-module/utils/index.js +0 -2
  97. package/build-module/utils/index.js.map +0 -1
  98. package/src/index.js +0 -2
  99. package/src/utils/index.js +0 -1
  100. package/src/utils/upload-media.js +0 -232
@@ -1,19 +1,18 @@
1
- /**
2
- * WordPress dependencies
3
- */
4
- import { createBlobURL } from '@wordpress/blob';
5
- import apiFetch from '@wordpress/api-fetch';
6
-
7
1
  /**
8
2
  * Internal dependencies
9
3
  */
10
- import { uploadMedia, getMimeTypesArray } from '../upload-media';
4
+ import { uploadMedia } from '../upload-media';
5
+ import { UploadError } from '../upload-error';
6
+ import { uploadToServer } from '../upload-to-server';
7
+
8
+ jest.mock( '../upload-to-server', () => ( {
9
+ uploadToServer: jest.fn(),
10
+ } ) );
11
11
 
12
12
  jest.mock( '@wordpress/blob', () => ( {
13
13
  createBlobURL: jest.fn(),
14
14
  revokeBlobURL: jest.fn(),
15
15
  } ) );
16
- jest.mock( '@wordpress/api-fetch', () => jest.fn() );
17
16
 
18
17
  const xmlFile = new window.File( [ 'fake_file' ], 'test.xml', {
19
18
  type: 'text/xml',
@@ -23,6 +22,10 @@ const imageFile = new window.File( [ 'fake_file' ], 'test.jpeg', {
23
22
  } );
24
23
 
25
24
  describe( 'uploadMedia', () => {
25
+ afterEach( () => {
26
+ jest.clearAllMocks();
27
+ } );
28
+
26
29
  it( 'should do nothing on no files', async () => {
27
30
  const onError = jest.fn();
28
31
  const onFileChange = jest.fn();
@@ -33,7 +36,7 @@ describe( 'uploadMedia', () => {
33
36
  } );
34
37
 
35
38
  expect( onError ).not.toHaveBeenCalled();
36
- expect( onFileChange ).not.toHaveBeenCalled();
39
+ expect( uploadToServer ).not.toHaveBeenCalled();
37
40
  } );
38
41
 
39
42
  it( 'should error if allowedTypes contains a partial mime type and the validation fails', async () => {
@@ -47,11 +50,14 @@ describe( 'uploadMedia', () => {
47
50
  } );
48
51
 
49
52
  expect( onError ).toHaveBeenCalledWith(
50
- expect.objectContaining( {
53
+ new UploadError( {
51
54
  code: 'MIME_TYPE_NOT_SUPPORTED',
55
+ message:
56
+ 'test.xml: Sorry, this file type is not supported here.',
57
+ file: xmlFile,
52
58
  } )
53
59
  );
54
- expect( onFileChange ).not.toHaveBeenCalled();
60
+ expect( uploadToServer ).not.toHaveBeenCalled();
55
61
  } );
56
62
 
57
63
  it( 'should error if allowedTypes contains a complete mime type and the validation fails', async () => {
@@ -65,17 +71,17 @@ describe( 'uploadMedia', () => {
65
71
  } );
66
72
 
67
73
  expect( onError ).toHaveBeenCalledWith(
68
- expect.objectContaining( {
74
+ new UploadError( {
69
75
  code: 'MIME_TYPE_NOT_SUPPORTED',
76
+ message:
77
+ 'test.jpeg: Sorry, this file type is not supported here.',
78
+ file: xmlFile,
70
79
  } )
71
80
  );
72
- expect( onFileChange ).not.toHaveBeenCalled();
81
+ expect( uploadToServer ).not.toHaveBeenCalled();
73
82
  } );
74
83
 
75
84
  it( 'should work if allowedTypes contains a complete mime type and the validation succeeds', async () => {
76
- createBlobURL.mockReturnValue( 'blob:fake_blob' );
77
- apiFetch.mockResolvedValue( { title: { raw: 'Test' } } );
78
-
79
85
  const onError = jest.fn();
80
86
  const onFileChange = jest.fn();
81
87
  await uploadMedia( {
@@ -83,10 +89,11 @@ describe( 'uploadMedia', () => {
83
89
  filesList: [ imageFile ],
84
90
  onError,
85
91
  onFileChange,
92
+ wpAllowedMimeTypes: { jpeg: 'image/jpeg' },
86
93
  } );
87
94
 
88
95
  expect( onError ).not.toHaveBeenCalled();
89
- expect( onFileChange ).toHaveBeenCalledTimes( 2 );
96
+ expect( uploadToServer ).toHaveBeenCalled();
90
97
  } );
91
98
 
92
99
  it( 'should error if allowedTypes contains multiple types and the validation fails', async () => {
@@ -100,17 +107,17 @@ describe( 'uploadMedia', () => {
100
107
  } );
101
108
 
102
109
  expect( onError ).toHaveBeenCalledWith(
103
- expect.objectContaining( {
110
+ new UploadError( {
104
111
  code: 'MIME_TYPE_NOT_SUPPORTED',
112
+ message:
113
+ 'test.xml: Sorry, this file type is not supported here.',
114
+ file: xmlFile,
105
115
  } )
106
116
  );
107
- expect( onFileChange ).not.toHaveBeenCalled();
117
+ expect( uploadToServer ).not.toHaveBeenCalled();
108
118
  } );
109
119
 
110
120
  it( 'should work if allowedTypes contains multiple types and the validation succeeds', async () => {
111
- createBlobURL.mockReturnValue( 'blob:fake_blob' );
112
- apiFetch.mockResolvedValue( { title: { raw: 'Test' } } );
113
-
114
121
  const onError = jest.fn();
115
122
  const onFileChange = jest.fn();
116
123
  await uploadMedia( {
@@ -118,16 +125,14 @@ describe( 'uploadMedia', () => {
118
125
  filesList: [ imageFile ],
119
126
  onError,
120
127
  onFileChange,
128
+ wpAllowedMimeTypes: { jpeg: 'image/jpeg', mp4: 'video/mp4' },
121
129
  } );
122
130
 
123
131
  expect( onError ).not.toHaveBeenCalled();
124
- expect( onFileChange ).toHaveBeenCalledTimes( 2 );
132
+ expect( uploadToServer ).toHaveBeenCalled();
125
133
  } );
126
134
 
127
135
  it( 'should only fail the invalid file and still allow others to succeed when uploading multiple files', async () => {
128
- createBlobURL.mockReturnValue( 'blob:fake_blob' );
129
- apiFetch.mockResolvedValue( { title: { raw: 'Test' } } );
130
-
131
136
  const onError = jest.fn();
132
137
  const onFileChange = jest.fn();
133
138
  await uploadMedia( {
@@ -135,15 +140,18 @@ describe( 'uploadMedia', () => {
135
140
  filesList: [ imageFile, xmlFile ],
136
141
  onError,
137
142
  onFileChange,
143
+ wpAllowedMimeTypes: { jpeg: 'image/jpeg' },
138
144
  } );
139
145
 
140
146
  expect( onError ).toHaveBeenCalledWith(
141
- expect.objectContaining( {
147
+ new UploadError( {
142
148
  code: 'MIME_TYPE_NOT_SUPPORTED',
149
+ message:
150
+ 'test.xml: Sorry, you are not allowed to upload this file type.',
143
151
  file: xmlFile,
144
152
  } )
145
153
  );
146
- expect( onFileChange ).toHaveBeenCalledTimes( 2 );
154
+ expect( uploadToServer ).toHaveBeenCalledTimes( 1 );
147
155
  } );
148
156
 
149
157
  it( 'should error if the file size is greater than the maximum', async () => {
@@ -155,19 +163,22 @@ describe( 'uploadMedia', () => {
155
163
  maxUploadFileSize: 1,
156
164
  onError,
157
165
  onFileChange,
166
+ wpAllowedMimeTypes: { jpeg: 'image/jpeg' },
158
167
  } );
159
168
 
160
169
  expect( onError ).toHaveBeenCalledWith(
161
- expect.objectContaining( {
170
+ new UploadError( {
162
171
  code: 'SIZE_ABOVE_LIMIT',
172
+ message:
173
+ 'test.jpeg: This file exceeds the maximum upload size for this site.',
174
+ file: imageFile,
163
175
  } )
164
176
  );
165
- expect( onFileChange ).not.toHaveBeenCalled();
177
+ expect( uploadToServer ).not.toHaveBeenCalled();
166
178
  } );
167
179
 
168
180
  it( 'should call error handler with the correct error object if file type is not allowed for user', async () => {
169
181
  const onError = jest.fn();
170
- const onFileChange = jest.fn();
171
182
  await uploadMedia( {
172
183
  allowedTypes: [ 'image' ],
173
184
  filesList: [ imageFile ],
@@ -176,53 +187,13 @@ describe( 'uploadMedia', () => {
176
187
  } );
177
188
 
178
189
  expect( onError ).toHaveBeenCalledWith(
179
- expect.objectContaining( {
190
+ new UploadError( {
180
191
  code: 'MIME_TYPE_NOT_ALLOWED_FOR_USER',
192
+ message:
193
+ 'test.jpeg: Sorry, you are not allowed to upload this file type.',
194
+ file: imageFile,
181
195
  } )
182
196
  );
183
- expect( onFileChange ).not.toHaveBeenCalled();
184
- } );
185
- } );
186
-
187
- describe( 'getMimeTypesArray', () => {
188
- it( 'should return the parameter passed if it is "falsy" e.g: undefined or null', () => {
189
- expect( getMimeTypesArray( null ) ).toEqual( null );
190
- expect( getMimeTypesArray( undefined ) ).toEqual( undefined );
191
- } );
192
-
193
- it( 'should return an empty array if an empty object is passed', () => {
194
- expect( getMimeTypesArray( {} ) ).toEqual( [] );
195
- } );
196
-
197
- it( 'should return the type plus a new mime type with type and subtype with the extension if a type is passed', () => {
198
- expect( getMimeTypesArray( { ext: 'chicken' } ) ).toEqual( [
199
- 'chicken',
200
- 'chicken/ext',
201
- ] );
202
- } );
203
-
204
- it( 'should return the mime type passed and a new mime type with type and the extension as subtype', () => {
205
- expect( getMimeTypesArray( { ext: 'chicken/ribs' } ) ).toEqual( [
206
- 'chicken/ribs',
207
- 'chicken/ext',
208
- ] );
209
- } );
210
-
211
- it( 'should return the mime type passed and an additional mime type per extension supported', () => {
212
- expect( getMimeTypesArray( { 'jpg|jpeg|jpe': 'image/jpeg' } ) ).toEqual(
213
- [ 'image/jpeg', 'image/jpg', 'image/jpeg', 'image/jpe' ]
214
- );
215
- } );
216
-
217
- it( 'should handle multiple mime types', () => {
218
- expect(
219
- getMimeTypesArray( { 'ext|aaa': 'chicken/ribs', aaa: 'bbb' } )
220
- ).toEqual( [
221
- 'chicken/ribs',
222
- 'chicken/ext',
223
- 'chicken/aaa',
224
- 'bbb',
225
- 'bbb/aaa',
226
- ] );
197
+ expect( uploadToServer ).not.toHaveBeenCalled();
227
198
  } );
228
199
  } );
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { validateFileSize } from '../validate-file-size';
5
+ import { UploadError } from '../upload-error';
6
+
7
+ const imageFile = new window.File( [ 'fake_file' ], 'test.jpeg', {
8
+ type: 'image/jpeg',
9
+ } );
10
+
11
+ const emptyFile = new window.File( [], 'test.jpeg', {
12
+ type: 'image/jpeg',
13
+ } );
14
+
15
+ describe( 'validateFileSize', () => {
16
+ afterEach( () => {
17
+ jest.clearAllMocks();
18
+ } );
19
+
20
+ it( 'should error if the file is empty', () => {
21
+ expect( () => {
22
+ validateFileSize( emptyFile );
23
+ } ).toThrow(
24
+ new UploadError( {
25
+ code: 'EMPTY_FILE',
26
+ message: 'test.jpeg: This file is empty.',
27
+ file: imageFile,
28
+ } )
29
+ );
30
+ } );
31
+
32
+ it( 'should error if the file is is greater than the maximum', () => {
33
+ expect( () => {
34
+ validateFileSize( imageFile, 2 );
35
+ } ).toThrow(
36
+ new UploadError( {
37
+ code: 'SIZE_ABOVE_LIMIT',
38
+ message:
39
+ 'test.jpeg: This file exceeds the maximum upload size for this site.',
40
+ file: imageFile,
41
+ } )
42
+ );
43
+ } );
44
+
45
+ it( 'should not error if the file is below the limit', () => {
46
+ expect( () => {
47
+ validateFileSize( imageFile, 100 );
48
+ } ).not.toThrow(
49
+ new UploadError( {
50
+ code: 'SIZE_ABOVE_LIMIT',
51
+ message:
52
+ 'test.jpeg: This file exceeds the maximum upload size for this site.',
53
+ file: imageFile,
54
+ } )
55
+ );
56
+ } );
57
+
58
+ it( 'should not error if there is no limit', () => {
59
+ expect( () => {
60
+ validateFileSize( imageFile );
61
+ } ).not.toThrow(
62
+ new UploadError( {
63
+ code: 'SIZE_ABOVE_LIMIT',
64
+ message:
65
+ 'test.jpeg: This file exceeds the maximum upload size for this site.',
66
+ file: imageFile,
67
+ } )
68
+ );
69
+ } );
70
+ } );
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { validateMimeTypeForUser } from '../validate-mime-type-for-user';
5
+ import { UploadError } from '../upload-error';
6
+
7
+ const imageFile = new window.File( [ 'fake_file' ], 'test.jpeg', {
8
+ type: 'image/jpeg',
9
+ } );
10
+
11
+ describe( 'validateMimeTypeForUser', () => {
12
+ afterEach( () => {
13
+ jest.clearAllMocks();
14
+ } );
15
+
16
+ it( 'should not error if wpAllowedMimeTypes is null or missing', async () => {
17
+ expect( () => {
18
+ validateMimeTypeForUser( imageFile );
19
+ } ).not.toThrow();
20
+ expect( () => {
21
+ validateMimeTypeForUser( imageFile, null );
22
+ } ).not.toThrow();
23
+ } );
24
+
25
+ it( 'should error if file type is not allowed for user', async () => {
26
+ expect( () => {
27
+ validateMimeTypeForUser( imageFile, { aac: 'audio/aac' } );
28
+ } ).toThrow(
29
+ new UploadError( {
30
+ code: 'MIME_TYPE_NOT_ALLOWED_FOR_USER',
31
+ message:
32
+ 'test.jpeg: Sorry, you are not allowed to upload this file type.',
33
+ file: imageFile,
34
+ } )
35
+ );
36
+ } );
37
+ } );
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { validateMimeType } from '../validate-mime-type';
5
+ import { UploadError } from '../upload-error';
6
+
7
+ const xmlFile = new window.File( [ 'fake_file' ], 'test.xml', {
8
+ type: 'text/xml',
9
+ } );
10
+ const imageFile = new window.File( [ 'fake_file' ], 'test.jpeg', {
11
+ type: 'image/jpeg',
12
+ } );
13
+
14
+ describe( 'validateMimeType', () => {
15
+ afterEach( () => {
16
+ jest.clearAllMocks();
17
+ } );
18
+
19
+ it( 'should error if allowedTypes contains a partial mime type and the validation fails', async () => {
20
+ expect( () => {
21
+ validateMimeType( xmlFile, [ 'image' ] );
22
+ } ).toThrow(
23
+ new UploadError( {
24
+ code: 'MIME_TYPE_NOT_SUPPORTED',
25
+ message:
26
+ 'test.xml: Sorry, this file type is not supported here.',
27
+ file: xmlFile,
28
+ } )
29
+ );
30
+ } );
31
+
32
+ it( 'should error if allowedTypes contains a complete mime type and the validation fails', async () => {
33
+ expect( () => {
34
+ validateMimeType( imageFile, [ 'image/gif' ] );
35
+ } ).toThrow(
36
+ new UploadError( {
37
+ code: 'MIME_TYPE_NOT_SUPPORTED',
38
+ message:
39
+ 'test.jpeg: Sorry, this file type is not supported here.',
40
+ file: xmlFile,
41
+ } )
42
+ );
43
+ } );
44
+
45
+ it( 'should error if allowedTypes contains multiple types and the validation fails', async () => {
46
+ expect( () => {
47
+ validateMimeType( xmlFile, [ 'video', 'image' ] );
48
+ } ).toThrow(
49
+ new UploadError( {
50
+ code: 'MIME_TYPE_NOT_SUPPORTED',
51
+ message:
52
+ 'test.xml: Sorry, this file type is not supported here.',
53
+ file: xmlFile,
54
+ } )
55
+ );
56
+ } );
57
+ } );
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { Attachment, RestAttachment } from './types';
5
+
6
+ /**
7
+ * Transforms an attachment object from the REST API shape into the shape expected by the block editor and other consumers.
8
+ *
9
+ * @param attachment REST API attachment object.
10
+ */
11
+ export function transformAttachment( attachment: RestAttachment ): Attachment {
12
+ // eslint-disable-next-line camelcase
13
+ const { alt_text, source_url, ...savedMediaProps } = attachment;
14
+ return {
15
+ ...savedMediaProps,
16
+ alt: attachment.alt_text,
17
+ caption: attachment.caption?.raw ?? '',
18
+ title: attachment.title.raw,
19
+ url: attachment.source_url,
20
+ poster:
21
+ attachment._embedded?.[ 'wp:featuredmedia' ]?.[ 0 ]?.source_url ||
22
+ undefined,
23
+ };
24
+ }
@@ -0,0 +1,207 @@
1
+ /**
2
+ * A media attachment object in a REST API context.
3
+ *
4
+ * Simplified version of what's defined in the wp-types package.
5
+ *
6
+ * @see https://www.npmjs.com/package/wp-types
7
+ */
8
+ interface WP_REST_API_Attachment {
9
+ /**
10
+ * Unique identifier for the attachment.
11
+ */
12
+ id: number;
13
+ /**
14
+ * The ID of the featured media for the post.
15
+ */
16
+ featured_media: number;
17
+ /**
18
+ * URL to the attachment.
19
+ */
20
+ link: string;
21
+ /**
22
+ * The date the attachment was published, in the site's timezone.
23
+ */
24
+ date: string;
25
+ /**
26
+ * The date the attachment was published, as GMT.
27
+ */
28
+ date_gmt: string;
29
+ /**
30
+ * The date the attachment was last modified, in the site's timezone.
31
+ */
32
+ modified: string;
33
+ /**
34
+ * The date the attachment was last modified, as GMT.
35
+ */
36
+ modified_gmt: string;
37
+ /**
38
+ * An alphanumeric identifier for the attachment unique to its type.
39
+ */
40
+ slug: string;
41
+ /**
42
+ * A named status for the attachment.
43
+ */
44
+ status: string;
45
+ /**
46
+ * Type of Post for the attachment.
47
+ */
48
+ type: 'attachment';
49
+ /**
50
+ * Alternative text to display when attachment is not displayed.
51
+ */
52
+ alt_text: string;
53
+ /**
54
+ * The attachment caption.
55
+ */
56
+ caption: {
57
+ /**
58
+ * Caption for the attachment, as it exists in the database. Only present when using the 'edit' context.
59
+ */
60
+ raw?: string;
61
+ /**
62
+ * HTML caption for the attachment, transformed for display.
63
+ */
64
+ rendered: string;
65
+ };
66
+ /**
67
+ * The attachment description.
68
+ */
69
+ description: {
70
+ /**
71
+ * Description for the attachment, as it exists in the database. Only present when using the 'edit' context.
72
+ */
73
+ raw?: string;
74
+ /**
75
+ * HTML description for the attachment, transformed for display.
76
+ */
77
+ rendered: string;
78
+ };
79
+ /**
80
+ * Attachment type.
81
+ */
82
+ media_type: 'image' | 'file';
83
+ /**
84
+ * The attachment MIME type.
85
+ */
86
+ mime_type: string;
87
+ /**
88
+ * Details about the media file, specific to its type.
89
+ */
90
+ media_details: {
91
+ [ k: string ]: unknown;
92
+ };
93
+ /**
94
+ * The ID for the associated post of the attachment.
95
+ */
96
+ post: number | null;
97
+ /**
98
+ * URL to the original attachment file.
99
+ */
100
+ source_url: string;
101
+ /**
102
+ * List of the missing image sizes of the attachment. Only present when using the 'edit' context.
103
+ */
104
+ missing_image_sizes?: string[];
105
+ /**
106
+ * Permalink template for the attachment. Only present when using the 'edit' context and the post type is public.
107
+ */
108
+ permalink_template?: string;
109
+ /**
110
+ * Slug automatically generated from the attachment title. Only present when using the 'edit' context and the post type is public.
111
+ */
112
+ generated_slug?: string;
113
+ /**
114
+ * An array of the class names for the post container element.
115
+ */
116
+ class_list: string[];
117
+ /**
118
+ * The title for the attachment.
119
+ */
120
+ title: {
121
+ /**
122
+ * Title for the attachment, as it exists in the database. Only present when using the 'edit' context.
123
+ */
124
+ raw?: string;
125
+ /**
126
+ * HTML title for the attachment, transformed for display.
127
+ */
128
+ rendered: string;
129
+ };
130
+ /**
131
+ * The ID for the author of the attachment.
132
+ */
133
+ author: number;
134
+ /**
135
+ * Whether or not comments are open on the attachment.
136
+ */
137
+ comment_status: string;
138
+ /**
139
+ * Whether or not the attachment can be pinged.
140
+ */
141
+ ping_status: string;
142
+ /**
143
+ * Meta fields.
144
+ */
145
+ meta:
146
+ | []
147
+ | {
148
+ [ k: string ]: unknown;
149
+ };
150
+ /**
151
+ * The theme file to use to display the attachment.
152
+ */
153
+ template: string;
154
+ _links: {
155
+ [ k: string ]: {
156
+ href: string;
157
+ embeddable?: boolean;
158
+ [ k: string ]: unknown;
159
+ }[];
160
+ };
161
+ /**
162
+ * The embedded representation of relations. Only present when the '_embed' query parameter is set.
163
+ */
164
+ _embedded?: {
165
+ /**
166
+ * The author of the post.
167
+ */
168
+ author: unknown[];
169
+ /**
170
+ * The featured image post.
171
+ */
172
+ 'wp:featuredmedia'?: WP_REST_API_Attachment[];
173
+ [ k: string ]: unknown;
174
+ };
175
+ [ k: string ]: unknown;
176
+ }
177
+
178
+ /**
179
+ * REST API attachment object with additional fields added by this project.
180
+ */
181
+ export interface RestAttachment extends WP_REST_API_Attachment {}
182
+
183
+ type BetterOmit< T, K extends PropertyKey > = {
184
+ [ P in keyof T as P extends K ? never : P ]: T[ P ];
185
+ };
186
+
187
+ /**
188
+ * Transformed attachment object.
189
+ */
190
+ export type Attachment = BetterOmit<
191
+ RestAttachment,
192
+ 'alt_text' | 'source_url' | 'caption' | 'title'
193
+ > & {
194
+ alt: WP_REST_API_Attachment[ 'alt_text' ];
195
+ caption: WP_REST_API_Attachment[ 'caption' ][ 'raw' ] & string;
196
+ title: WP_REST_API_Attachment[ 'title' ][ 'raw' ];
197
+ url: WP_REST_API_Attachment[ 'source_url' ];
198
+ poster?: WP_REST_API_Attachment[ 'source_url' ];
199
+ };
200
+
201
+ export type OnChangeHandler = ( attachments: Partial< Attachment >[] ) => void;
202
+ export type OnSuccessHandler = ( attachments: Partial< Attachment >[] ) => void;
203
+ export type OnErrorHandler = ( error: Error ) => void;
204
+
205
+ export type CreateRestAttachment = Partial< RestAttachment >;
206
+
207
+ export type AdditionalData = BetterOmit< CreateRestAttachment, 'meta' >;
@@ -0,0 +1,26 @@
1
+ interface UploadErrorArgs {
2
+ code: string;
3
+ message: string;
4
+ file: File;
5
+ cause?: Error;
6
+ }
7
+
8
+ /**
9
+ * MediaError class.
10
+ *
11
+ * Small wrapper around the `Error` class
12
+ * to hold an error code and a reference to a file object.
13
+ */
14
+ export class UploadError extends Error {
15
+ code: string;
16
+ file: File;
17
+
18
+ constructor( { code, message, file, cause }: UploadErrorArgs ) {
19
+ super( message, { cause } );
20
+
21
+ Object.setPrototypeOf( this, new.target.prototype );
22
+
23
+ this.code = code;
24
+ this.file = file;
25
+ }
26
+ }