@wordpress/api-fetch 7.29.1-next.f34ab90e9.0 → 7.30.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 (97) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/index.js +50 -51
  3. package/build/index.js.map +1 -1
  4. package/build/middlewares/fetch-all-middleware.js +14 -14
  5. package/build/middlewares/fetch-all-middleware.js.map +1 -1
  6. package/build/middlewares/http-v1.js +6 -5
  7. package/build/middlewares/http-v1.js.map +1 -1
  8. package/build/middlewares/media-upload.js +7 -7
  9. package/build/middlewares/media-upload.js.map +1 -1
  10. package/build/middlewares/namespace-endpoint.js +2 -1
  11. package/build/middlewares/namespace-endpoint.js.map +1 -1
  12. package/build/middlewares/nonce.js +7 -5
  13. package/build/middlewares/nonce.js.map +1 -1
  14. package/build/middlewares/preloading.js +10 -7
  15. package/build/middlewares/preloading.js.map +1 -1
  16. package/build/middlewares/root-url.js +2 -2
  17. package/build/middlewares/root-url.js.map +1 -1
  18. package/build/middlewares/theme-preview.js +6 -2
  19. package/build/middlewares/theme-preview.js.map +1 -1
  20. package/build/middlewares/user-locale.js +2 -1
  21. package/build/middlewares/user-locale.js.map +1 -1
  22. package/build/types.js.map +1 -1
  23. package/build/utils/response.js +31 -50
  24. package/build/utils/response.js.map +1 -1
  25. package/build-module/index.js +38 -52
  26. package/build-module/index.js.map +1 -1
  27. package/build-module/middlewares/fetch-all-middleware.js +14 -15
  28. package/build-module/middlewares/fetch-all-middleware.js.map +1 -1
  29. package/build-module/middlewares/http-v1.js +6 -5
  30. package/build-module/middlewares/http-v1.js.map +1 -1
  31. package/build-module/middlewares/media-upload.js +7 -8
  32. package/build-module/middlewares/media-upload.js.map +1 -1
  33. package/build-module/middlewares/namespace-endpoint.js +2 -1
  34. package/build-module/middlewares/namespace-endpoint.js.map +1 -1
  35. package/build-module/middlewares/nonce.js +7 -5
  36. package/build-module/middlewares/nonce.js.map +1 -1
  37. package/build-module/middlewares/preloading.js +10 -7
  38. package/build-module/middlewares/preloading.js.map +1 -1
  39. package/build-module/middlewares/root-url.js +3 -2
  40. package/build-module/middlewares/root-url.js.map +1 -1
  41. package/build-module/middlewares/theme-preview.js +5 -2
  42. package/build-module/middlewares/theme-preview.js.map +1 -1
  43. package/build-module/middlewares/user-locale.js +2 -1
  44. package/build-module/middlewares/user-locale.js.map +1 -1
  45. package/build-module/types.js.map +1 -1
  46. package/build-module/utils/response.js +30 -48
  47. package/build-module/utils/response.js.map +1 -1
  48. package/build-types/index.d.ts +25 -32
  49. package/build-types/index.d.ts.map +1 -1
  50. package/build-types/middlewares/fetch-all-middleware.d.ts +5 -4
  51. package/build-types/middlewares/fetch-all-middleware.d.ts.map +1 -1
  52. package/build-types/middlewares/http-v1.d.ts +8 -3
  53. package/build-types/middlewares/http-v1.d.ts.map +1 -1
  54. package/build-types/middlewares/media-upload.d.ts +5 -4
  55. package/build-types/middlewares/media-upload.d.ts.map +1 -1
  56. package/build-types/middlewares/namespace-endpoint.d.ts +4 -3
  57. package/build-types/middlewares/namespace-endpoint.d.ts.map +1 -1
  58. package/build-types/middlewares/nonce.d.ts +9 -4
  59. package/build-types/middlewares/nonce.d.ts.map +1 -1
  60. package/build-types/middlewares/preloading.d.ts +8 -4
  61. package/build-types/middlewares/preloading.d.ts.map +1 -1
  62. package/build-types/middlewares/root-url.d.ts +8 -4
  63. package/build-types/middlewares/root-url.d.ts.map +1 -1
  64. package/build-types/middlewares/theme-preview.d.ts +8 -4
  65. package/build-types/middlewares/theme-preview.d.ts.map +1 -1
  66. package/build-types/middlewares/user-locale.d.ts +4 -3
  67. package/build-types/middlewares/user-locale.d.ts.map +1 -1
  68. package/build-types/types.d.ts +4 -3
  69. package/build-types/types.d.ts.map +1 -1
  70. package/build-types/utils/response.d.ts +13 -5
  71. package/build-types/utils/response.d.ts.map +1 -1
  72. package/package.json +4 -4
  73. package/src/{index.js → index.ts} +78 -69
  74. package/src/middlewares/{fetch-all-middleware.js → fetch-all-middleware.ts} +24 -20
  75. package/src/middlewares/{http-v1.js → http-v1.ts} +8 -6
  76. package/src/middlewares/{media-upload.js → media-upload.ts} +13 -12
  77. package/src/middlewares/{namespace-endpoint.js → namespace-endpoint.ts} +7 -2
  78. package/src/middlewares/{nonce.js → nonce.ts} +15 -7
  79. package/src/middlewares/{preloading.js → preloading.ts} +21 -11
  80. package/src/middlewares/root-url.ts +47 -0
  81. package/src/middlewares/test/{fetch-all-middleware.js → fetch-all-middleware.ts} +1 -1
  82. package/src/middlewares/test/{http-v1.js → http-v1.ts} +7 -4
  83. package/src/middlewares/test/{media-upload.js → media-upload.ts} +2 -1
  84. package/src/middlewares/test/{namespace-endpoint.js → namespace-endpoint.ts} +2 -1
  85. package/src/middlewares/test/{nonce.js → nonce.ts} +5 -4
  86. package/src/middlewares/test/{preloading.js → preloading.ts} +31 -11
  87. package/src/middlewares/test/{root-url.js → root-url.ts} +2 -1
  88. package/src/middlewares/test/{user-locale.js → user-locale.ts} +9 -8
  89. package/src/middlewares/theme-preview.ts +60 -0
  90. package/src/middlewares/{user-locale.js → user-locale.ts} +4 -2
  91. package/src/test/index.js +218 -147
  92. package/src/types.ts +10 -5
  93. package/src/utils/response.ts +64 -0
  94. package/tsconfig.tsbuildinfo +1 -1
  95. package/src/middlewares/root-url.js +0 -44
  96. package/src/middlewares/theme-preview.js +0 -42
  97. package/src/utils/response.js +0 -85
@@ -10,12 +10,13 @@ import {
10
10
  parseAndThrowError,
11
11
  parseResponseAndNormalizeError,
12
12
  } from '../utils/response';
13
+ import type { APIFetchOptions, APIFetchMiddleware } from '../types';
13
14
 
14
15
  /**
15
- * @param {import('../types').APIFetchOptions} options
16
- * @return {boolean} True if the request is for media upload.
16
+ * @param options
17
+ * @return True if the request is for media upload.
17
18
  */
18
- function isMediaUploadRequest( options ) {
19
+ function isMediaUploadRequest( options: APIFetchOptions ) {
19
20
  const isCreateMethod = !! options.method && options.method === 'POST';
20
21
  const isMediaEndpoint =
21
22
  ( !! options.path && options.path.indexOf( '/wp/v2/media' ) !== -1 ) ||
@@ -26,10 +27,10 @@ function isMediaUploadRequest( options ) {
26
27
 
27
28
  /**
28
29
  * Middleware handling media upload failures and retries.
29
- *
30
- * @type {import('../types').APIFetchMiddleware}
30
+ * @param options
31
+ * @param next
31
32
  */
32
- const mediaUploadMiddleware = ( options, next ) => {
33
+ const mediaUploadMiddleware: APIFetchMiddleware = ( options, next ) => {
33
34
  if ( ! isMediaUploadRequest( options ) ) {
34
35
  return next( options );
35
36
  }
@@ -38,10 +39,10 @@ const mediaUploadMiddleware = ( options, next ) => {
38
39
  const maxRetries = 5;
39
40
 
40
41
  /**
41
- * @param {string} attachmentId
42
- * @return {Promise<any>} Processed post response.
42
+ * @param attachmentId
43
+ * @return Processed post response.
43
44
  */
44
- const postProcess = ( attachmentId ) => {
45
+ const postProcess = ( attachmentId: string ): Promise< any > => {
45
46
  retries++;
46
47
  return next( {
47
48
  path: `/wp/v2/media/${ attachmentId }/post-process`,
@@ -62,9 +63,9 @@ const mediaUploadMiddleware = ( options, next ) => {
62
63
  };
63
64
 
64
65
  return next( { ...options, parse: false } )
65
- .catch( ( response ) => {
66
+ .catch( ( response: Response ) => {
66
67
  // `response` could actually be an error thrown by `defaultFetchHandler`.
67
- if ( ! response.headers ) {
68
+ if ( ! ( response instanceof globalThis.Response ) ) {
68
69
  return Promise.reject( response );
69
70
  }
70
71
 
@@ -91,7 +92,7 @@ const mediaUploadMiddleware = ( options, next ) => {
91
92
  }
92
93
  return parseAndThrowError( response, options.parse );
93
94
  } )
94
- .then( ( response ) =>
95
+ .then( ( response: Response ) =>
95
96
  parseResponseAndNormalizeError( response, options.parse )
96
97
  );
97
98
  };
@@ -1,7 +1,12 @@
1
1
  /**
2
- * @type {import('../types').APIFetchMiddleware}
2
+ * Internal dependencies
3
3
  */
4
- const namespaceAndEndpointMiddleware = ( options, next ) => {
4
+ import type { APIFetchMiddleware } from '../types';
5
+
6
+ const namespaceAndEndpointMiddleware: APIFetchMiddleware = (
7
+ options,
8
+ next
9
+ ) => {
5
10
  let path = options.path;
6
11
  let namespaceTrimmed, endpointTrimmed;
7
12
 
@@ -1,12 +1,20 @@
1
1
  /**
2
- * @param {string} nonce
3
- * @return {import('../types').APIFetchMiddleware & { nonce: string }} A middleware to enhance a request with a nonce.
2
+ * Internal dependencies
4
3
  */
5
- function createNonceMiddleware( nonce ) {
6
- /**
7
- * @type {import('../types').APIFetchMiddleware & { nonce: string }}
8
- */
9
- const middleware = ( options, next ) => {
4
+ import type { APIFetchMiddleware } from '../types';
5
+
6
+ /**
7
+ * @param nonce
8
+ *
9
+ * @return A middleware to enhance a request with a nonce.
10
+ */
11
+ function createNonceMiddleware(
12
+ nonce: string
13
+ ): APIFetchMiddleware & { nonce: string } {
14
+ const middleware: APIFetchMiddleware & { nonce: string } = (
15
+ options,
16
+ next
17
+ ) => {
10
18
  const { headers = {} } = options;
11
19
 
12
20
  // If an 'X-WP-Nonce' header (or any case-insensitive variation
@@ -4,10 +4,17 @@
4
4
  import { addQueryArgs, getQueryArgs, normalizePath } from '@wordpress/url';
5
5
 
6
6
  /**
7
- * @param {Record<string, any>} preloadedData
8
- * @return {import('../types').APIFetchMiddleware} Preloading middleware.
7
+ * Internal dependencies
9
8
  */
10
- function createPreloadingMiddleware( preloadedData ) {
9
+ import type { APIFetchMiddleware } from '../types';
10
+
11
+ /**
12
+ * @param preloadedData
13
+ * @return Preloading middleware.
14
+ */
15
+ function createPreloadingMiddleware(
16
+ preloadedData: Record< string, any >
17
+ ): APIFetchMiddleware {
11
18
  const cache = Object.fromEntries(
12
19
  Object.entries( preloadedData ).map( ( [ path, data ] ) => [
13
20
  normalizePath( path ),
@@ -17,7 +24,6 @@ function createPreloadingMiddleware( preloadedData ) {
17
24
 
18
25
  return ( options, next ) => {
19
26
  const { parse = true } = options;
20
- /** @type {string | void} */
21
27
  let rawPath = options.path;
22
28
  if ( ! rawPath && options.url ) {
23
29
  const { rest_route: pathFromQuery, ...queryArgs } = getQueryArgs(
@@ -63,11 +69,14 @@ function createPreloadingMiddleware( preloadedData ) {
63
69
  /**
64
70
  * This is a helper function that sends a success response.
65
71
  *
66
- * @param {Record<string, any>} responseData
67
- * @param {boolean} parse
68
- * @return {Promise<any>} Promise with the response.
72
+ * @param responseData
73
+ * @param parse
74
+ * @return Promise with the response.
69
75
  */
70
- function prepareResponse( responseData, parse ) {
76
+ function prepareResponse(
77
+ responseData: Record< string, any >,
78
+ parse: boolean
79
+ ) {
71
80
  if ( parse ) {
72
81
  return Promise.resolve( responseData.body );
73
82
  }
@@ -82,12 +91,13 @@ function prepareResponse( responseData, parse ) {
82
91
  );
83
92
  } catch {
84
93
  // See: https://github.com/WordPress/gutenberg/issues/67358#issuecomment-2621163926.
85
- Object.entries( responseData.headers ).forEach( ( [ key, value ] ) => {
94
+ Object.entries(
95
+ responseData.headers as Record< string, string >
96
+ ).forEach( ( [ key, value ] ) => {
86
97
  if ( key.toLowerCase() === 'link' ) {
87
98
  responseData.headers[ key ] = value.replace(
88
99
  /<([^>]+)>/,
89
- ( /** @type {any} */ _, /** @type {string} */ url ) =>
90
- `<${ encodeURI( url ) }>`
100
+ ( _, url ) => `<${ encodeURI( url ) }>`
91
101
  );
92
102
  }
93
103
  } );
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { APIFetchMiddleware } from '../types';
5
+ import namespaceAndEndpointMiddleware from './namespace-endpoint';
6
+
7
+ /**
8
+ * @param rootURL
9
+ * @return Root URL middleware.
10
+ */
11
+ const createRootURLMiddleware =
12
+ ( rootURL: string ): APIFetchMiddleware =>
13
+ ( options, next ) => {
14
+ return namespaceAndEndpointMiddleware( options, ( optionsWithPath ) => {
15
+ let url = optionsWithPath.url;
16
+ let path = optionsWithPath.path;
17
+ let apiRoot;
18
+
19
+ if ( typeof path === 'string' ) {
20
+ apiRoot = rootURL;
21
+
22
+ if ( -1 !== rootURL.indexOf( '?' ) ) {
23
+ path = path.replace( '?', '&' );
24
+ }
25
+
26
+ path = path.replace( /^\//, '' );
27
+
28
+ // API root may already include query parameter prefix if site is
29
+ // configured to use plain permalinks.
30
+ if (
31
+ 'string' === typeof apiRoot &&
32
+ -1 !== apiRoot.indexOf( '?' )
33
+ ) {
34
+ path = path.replace( '?', '&' );
35
+ }
36
+
37
+ url = apiRoot + path;
38
+ }
39
+
40
+ return next( {
41
+ ...optionsWithPath,
42
+ url,
43
+ } );
44
+ } );
45
+ };
46
+
47
+ export default createRootURLMiddleware;
@@ -19,7 +19,7 @@ describe( 'Fetch All Middleware', () => {
19
19
  expect.hasAssertions();
20
20
  const originalOptions = { url: '/posts?per_page=-1' };
21
21
  let counter = 1;
22
- jest.doMock( '../../index.js', () => ( options ) => {
22
+ jest.doMock( '../../index.ts', () => ( options ) => {
23
23
  const expectedUrl =
24
24
  counter === 1
25
25
  ? '/posts?per_page=100'
@@ -1,15 +1,18 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
+ import type { FetchHandler } from '../../types';
4
5
  import httpV1Middleware from '../http-v1';
5
6
 
6
7
  describe( 'HTTP v1 Middleware', () => {
7
8
  it( 'should use a POST for a PUT requests', () => {
8
9
  expect.hasAssertions();
9
10
 
10
- const callback = ( options ) => {
11
+ const callback: FetchHandler = async ( options ) => {
11
12
  expect( options.method ).toBe( 'POST' );
12
- expect( options.headers[ 'X-HTTP-Method-Override' ] ).toBe( 'PUT' );
13
+ expect( options.headers![ 'X-HTTP-Method-Override' ] ).toBe(
14
+ 'PUT'
15
+ );
13
16
  };
14
17
 
15
18
  httpV1Middleware( { method: 'PUT', data: {} }, callback );
@@ -19,7 +22,7 @@ describe( 'HTTP v1 Middleware', () => {
19
22
  expect.hasAssertions();
20
23
 
21
24
  const requestOptions = { method: 'GET', path: '/wp/v2/posts' };
22
- const callback = ( options ) => {
25
+ const callback: FetchHandler = async ( options ) => {
23
26
  expect( options ).toBe( requestOptions );
24
27
  };
25
28
 
@@ -30,7 +33,7 @@ describe( 'HTTP v1 Middleware', () => {
30
33
  expect.hasAssertions();
31
34
 
32
35
  const requestOptions = { path: '/wp/v2/posts' };
33
- const callback = ( options ) => {
36
+ const callback: FetchHandler = async ( options ) => {
34
37
  expect( options ).toBe( requestOptions );
35
38
  };
36
39
 
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
+ import type { FetchHandler } from '../../types';
4
5
  import mediaUploadMiddleware from '../media-upload';
5
6
 
6
7
  describe( 'Media Upload Middleware', () => {
@@ -8,7 +9,7 @@ describe( 'Media Upload Middleware', () => {
8
9
  expect.hasAssertions();
9
10
 
10
11
  const originalOptions = { path: '/wp/v2/media' };
11
- const next = ( options ) => {
12
+ const next: FetchHandler = async ( options ) => {
12
13
  expect( options ).toBe( originalOptions );
13
14
  };
14
15
 
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
+ import type { FetchHandler } from '../../types';
4
5
  import namespaceEndpointMiddleware from '../namespace-endpoint';
5
6
 
6
7
  describe( 'Namespace & Endpoint middleware', () => {
@@ -12,7 +13,7 @@ describe( 'Namespace & Endpoint middleware', () => {
12
13
  namespace: '/wp/v2',
13
14
  endpoint: '/posts',
14
15
  };
15
- const callback = ( options ) => {
16
+ const callback: FetchHandler = async ( options ) => {
16
17
  expect( options.path ).toBe( 'wp/v2/posts' );
17
18
  expect( options.namespace ).toBeUndefined();
18
19
  expect( options.endpoint ).toBeUndefined();
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
+ import type { FetchHandler } from '../../types';
4
5
  import createNonceMiddleware from '../nonce';
5
6
 
6
7
  describe( 'Nonce middleware', () => {
@@ -13,8 +14,8 @@ describe( 'Nonce middleware', () => {
13
14
  method: 'GET',
14
15
  path: '/wp/v2/posts',
15
16
  };
16
- const callback = ( options ) => {
17
- expect( options.headers[ 'X-WP-Nonce' ] ).toBe( nonce );
17
+ const callback: FetchHandler = async ( options ) => {
18
+ expect( options.headers![ 'X-WP-Nonce' ] ).toBe( nonce );
18
19
  };
19
20
 
20
21
  nonceMiddleware( requestOptions, callback );
@@ -31,8 +32,8 @@ describe( 'Nonce middleware', () => {
31
32
  headers: { 'X-WP-Nonce': 'existing nonce' },
32
33
  };
33
34
 
34
- const callback = ( options ) => {
35
- expect( options.headers[ 'X-WP-Nonce' ] ).toBe( 'new nonce' );
35
+ const callback: FetchHandler = async ( options ) => {
36
+ expect( options.headers![ 'X-WP-Nonce' ] ).toBe( 'new nonce' );
36
37
  };
37
38
 
38
39
  nonceMiddleware( requestOptions, callback );
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
+ import type { FetchHandler } from '../../types';
4
5
  import createPreloadingMiddleware from '../preloading';
5
6
 
6
7
  describe( 'Preloading Middleware', () => {
@@ -23,7 +24,10 @@ describe( 'Preloading Middleware', () => {
23
24
  path: 'wp/v2/posts',
24
25
  };
25
26
 
26
- const response = preloadingMiddleware( requestOptions );
27
+ const response = preloadingMiddleware(
28
+ requestOptions,
29
+ async () => {}
30
+ );
27
31
  return response.then( ( value ) => {
28
32
  expect( value ).toEqual( body );
29
33
  } );
@@ -60,9 +64,12 @@ describe( 'Preloading Middleware', () => {
60
64
  const noResponseMock =
61
65
  'undefined' === typeof window.Response;
62
66
  if ( noResponseMock ) {
67
+ // @ts-expect-error
63
68
  window.Response = class {
64
69
  constructor( body, options ) {
70
+ // @ts-expect-error
65
71
  this.body = JSON.parse( body );
72
+ // @ts-expect-error
66
73
  this.headers = options.headers;
67
74
  }
68
75
  };
@@ -92,8 +99,12 @@ describe( 'Preloading Middleware', () => {
92
99
  parse: false,
93
100
  };
94
101
 
95
- const response = preloadingMiddleware( requestOptions );
102
+ const response = preloadingMiddleware(
103
+ requestOptions,
104
+ async () => {}
105
+ );
96
106
  if ( noResponseMock ) {
107
+ // @ts-expect-error
97
108
  delete window.Response;
98
109
  }
99
110
  return response.then( ( value ) => {
@@ -126,7 +137,10 @@ describe( 'Preloading Middleware', () => {
126
137
  parse: true,
127
138
  };
128
139
 
129
- const response = preloadingMiddleware( requestOptions );
140
+ const response = preloadingMiddleware(
141
+ requestOptions,
142
+ async () => {}
143
+ );
130
144
  return response.then( ( value ) => {
131
145
  expect( value ).toEqual( body );
132
146
  } );
@@ -172,7 +186,10 @@ describe( 'Preloading Middleware', () => {
172
186
  path: 'wp/v2/demo-reverse-alphabetical?baz=quux&foo=bar',
173
187
  };
174
188
 
175
- let value = await preloadingMiddleware( requestOptions, () => {} );
189
+ let value = await preloadingMiddleware(
190
+ requestOptions,
191
+ async () => {}
192
+ );
176
193
  expect( value ).toEqual( body );
177
194
 
178
195
  requestOptions = {
@@ -180,7 +197,7 @@ describe( 'Preloading Middleware', () => {
180
197
  path: 'wp/v2/demo-alphabetical?foo=bar&baz=quux',
181
198
  };
182
199
 
183
- value = await preloadingMiddleware( requestOptions, () => {} );
200
+ value = await preloadingMiddleware( requestOptions, async () => {} );
184
201
  expect( value ).toEqual( body );
185
202
  } );
186
203
 
@@ -196,7 +213,7 @@ describe( 'Preloading Middleware', () => {
196
213
  method: 'GET',
197
214
  path: '/?_fields=foo%2Cbar',
198
215
  },
199
- () => {}
216
+ async () => {}
200
217
  );
201
218
 
202
219
  expect( response ).toEqual( body );
@@ -214,7 +231,7 @@ describe( 'Preloading Middleware', () => {
214
231
  method: 'GET',
215
232
  url: '/index.php?rest_route=%2F',
216
233
  },
217
- () => {}
234
+ async () => {}
218
235
  );
219
236
 
220
237
  expect( response ).toEqual( body );
@@ -232,7 +249,7 @@ describe( 'Preloading Middleware', () => {
232
249
  method: 'GET',
233
250
  url: '/index.php?rest_route=%2F&_fields=foo%2Cbar',
234
251
  },
235
- () => {}
252
+ async () => {}
236
253
  );
237
254
 
238
255
  expect( response ).toEqual( body );
@@ -321,7 +338,7 @@ describe( 'Preloading Middleware', () => {
321
338
  [ 'all empty', {} ],
322
339
  [ 'method empty', { [ method ]: {} } ],
323
340
  ] )( '%s', ( label, preloadedData ) => {
324
- it( 'should move to the next middleware if no preloaded data', () => {
341
+ it( 'should move to the next middleware if no preloaded data', async () => {
325
342
  const preloadingMiddleware =
326
343
  createPreloadingMiddleware( preloadedData );
327
344
  const requestOptions = {
@@ -329,12 +346,15 @@ describe( 'Preloading Middleware', () => {
329
346
  path: 'wp/v2/posts',
330
347
  };
331
348
 
332
- const callback = ( options ) => {
349
+ const callback: FetchHandler = async ( options ) => {
333
350
  expect( options ).toBe( requestOptions );
334
351
  return true;
335
352
  };
336
353
 
337
- const ret = preloadingMiddleware( requestOptions, callback );
354
+ const ret = await preloadingMiddleware(
355
+ requestOptions,
356
+ callback
357
+ );
338
358
  expect( ret ).toBe( true );
339
359
  } );
340
360
  } );
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
+ import type { FetchHandler } from '../../types';
4
5
  import createRootUrlMiddleware from '../root-url';
5
6
 
6
7
  describe( 'Root URL middleware', () => {
@@ -13,7 +14,7 @@ describe( 'Root URL middleware', () => {
13
14
  method: 'GET',
14
15
  path: '/wp/v2/posts',
15
16
  };
16
- const callback = ( options ) => {
17
+ const callback: FetchHandler = async ( options ) => {
17
18
  expect( options.url ).toBe(
18
19
  'http://wp.org/wp-admin/rest/wp/v2/posts'
19
20
  );
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
+ import type { FetchHandler } from '../../types';
4
5
  import userLocaleMiddleware from '../user-locale';
5
6
 
6
7
  describe( 'User locale middleware', () => {
@@ -12,7 +13,7 @@ describe( 'User locale middleware', () => {
12
13
  path: '/wp/v2/posts',
13
14
  };
14
15
 
15
- const callback = ( options ) => {
16
+ const callback: FetchHandler = async ( options ) => {
16
17
  expect( options.path ).toBe( '/wp/v2/posts?_locale=user' );
17
18
  };
18
19
 
@@ -27,7 +28,7 @@ describe( 'User locale middleware', () => {
27
28
  path: '/wp/v2/posts?foo=bar',
28
29
  };
29
30
 
30
- const callback = ( options ) => {
31
+ const callback: FetchHandler = async ( options ) => {
31
32
  expect( options.path ).toBe( '/wp/v2/posts?foo=bar&_locale=user' );
32
33
  };
33
34
 
@@ -42,7 +43,7 @@ describe( 'User locale middleware', () => {
42
43
  path: '/wp/v2/posts?_locale=foo',
43
44
  };
44
45
 
45
- const callback = ( options ) => {
46
+ const callback: FetchHandler = async ( options ) => {
46
47
  expect( options.path ).toBe( '/wp/v2/posts?_locale=foo' );
47
48
  };
48
49
 
@@ -57,7 +58,7 @@ describe( 'User locale middleware', () => {
57
58
  path: '/wp/v2/posts?foo=bar&_locale=foo',
58
59
  };
59
60
 
60
- const callback = ( options ) => {
61
+ const callback: FetchHandler = async ( options ) => {
61
62
  expect( options.path ).toBe( '/wp/v2/posts?foo=bar&_locale=foo' );
62
63
  };
63
64
 
@@ -72,7 +73,7 @@ describe( 'User locale middleware', () => {
72
73
  url: 'http://wp.org/wp-json/wp/v2/posts',
73
74
  };
74
75
 
75
- const callback = ( options ) => {
76
+ const callback: FetchHandler = async ( options ) => {
76
77
  expect( options.url ).toBe(
77
78
  'http://wp.org/wp-json/wp/v2/posts?_locale=user'
78
79
  );
@@ -89,7 +90,7 @@ describe( 'User locale middleware', () => {
89
90
  url: 'http://wp.org/wp-json/wp/v2/posts?foo=bar',
90
91
  };
91
92
 
92
- const callback = ( options ) => {
93
+ const callback: FetchHandler = async ( options ) => {
93
94
  expect( options.url ).toBe(
94
95
  'http://wp.org/wp-json/wp/v2/posts?foo=bar&_locale=user'
95
96
  );
@@ -106,7 +107,7 @@ describe( 'User locale middleware', () => {
106
107
  url: 'http://wp.org/wp-json/wp/v2/posts?_locale=foo',
107
108
  };
108
109
 
109
- const callback = ( options ) => {
110
+ const callback: FetchHandler = async ( options ) => {
110
111
  expect( options.url ).toBe(
111
112
  'http://wp.org/wp-json/wp/v2/posts?_locale=foo'
112
113
  );
@@ -123,7 +124,7 @@ describe( 'User locale middleware', () => {
123
124
  url: 'http://wp.org/wp-json/wp/v2/posts?foo=bar&_locale=foo',
124
125
  };
125
126
 
126
- const callback = ( options ) => {
127
+ const callback: FetchHandler = async ( options ) => {
127
128
  expect( options.url ).toBe(
128
129
  'http://wp.org/wp-json/wp/v2/posts?foo=bar&_locale=foo'
129
130
  );
@@ -0,0 +1,60 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { addQueryArgs, getQueryArg, removeQueryArgs } from '@wordpress/url';
5
+ /**
6
+ * Internal dependencies
7
+ */
8
+ import type { APIFetchMiddleware } from '../types';
9
+
10
+ /**
11
+ * This appends a `wp_theme_preview` parameter to the REST API request URL if
12
+ * the admin URL contains a `theme` GET parameter.
13
+ *
14
+ * If the REST API request URL has contained the `wp_theme_preview` parameter as `''`,
15
+ * then bypass this middleware.
16
+ *
17
+ * @param themePath
18
+ * @return Preloading middleware.
19
+ */
20
+ const createThemePreviewMiddleware =
21
+ ( themePath: Record< string, any > ): APIFetchMiddleware =>
22
+ ( options, next ) => {
23
+ if ( typeof options.url === 'string' ) {
24
+ const wpThemePreview = getQueryArg(
25
+ options.url,
26
+ 'wp_theme_preview'
27
+ );
28
+ if ( wpThemePreview === undefined ) {
29
+ options.url = addQueryArgs( options.url, {
30
+ wp_theme_preview: themePath,
31
+ } );
32
+ } else if ( wpThemePreview === '' ) {
33
+ options.url = removeQueryArgs(
34
+ options.url,
35
+ 'wp_theme_preview'
36
+ );
37
+ }
38
+ }
39
+
40
+ if ( typeof options.path === 'string' ) {
41
+ const wpThemePreview = getQueryArg(
42
+ options.path,
43
+ 'wp_theme_preview'
44
+ );
45
+ if ( wpThemePreview === undefined ) {
46
+ options.path = addQueryArgs( options.path, {
47
+ wp_theme_preview: themePath,
48
+ } );
49
+ } else if ( wpThemePreview === '' ) {
50
+ options.path = removeQueryArgs(
51
+ options.path,
52
+ 'wp_theme_preview'
53
+ );
54
+ }
55
+ }
56
+
57
+ return next( options );
58
+ };
59
+
60
+ export default createThemePreviewMiddleware;
@@ -4,9 +4,11 @@
4
4
  import { addQueryArgs, hasQueryArg } from '@wordpress/url';
5
5
 
6
6
  /**
7
- * @type {import('../types').APIFetchMiddleware}
7
+ * Internal dependencies
8
8
  */
9
- const userLocaleMiddleware = ( options, next ) => {
9
+ import type { APIFetchMiddleware } from '../types';
10
+
11
+ const userLocaleMiddleware: APIFetchMiddleware = ( options, next ) => {
10
12
  if (
11
13
  typeof options.url === 'string' &&
12
14
  ! hasQueryArg( options.url, '_locale' )