@wordpress/api-fetch 7.46.0 → 7.47.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 7.47.0 (2026-05-27)
6
+
5
7
  ## 7.46.0 (2026-05-14)
6
8
 
7
9
  ## 7.45.0 (2026-04-29)
package/build/index.cjs CHANGED
@@ -34,6 +34,7 @@ __export(index_exports, {
34
34
  });
35
35
  module.exports = __toCommonJS(index_exports);
36
36
  var import_i18n = require("@wordpress/i18n");
37
+ var import_lock_unlock = require("./lock-unlock.cjs");
37
38
  var import_nonce = __toESM(require("./middlewares/nonce.cjs"));
38
39
  var import_root_url = __toESM(require("./middlewares/root-url.cjs"));
39
40
  var import_preloading = __toESM(require("./middlewares/preloading.cjs"));
@@ -63,6 +64,16 @@ var middlewares = [
63
64
  function registerMiddleware(middleware) {
64
65
  middlewares.unshift(middleware);
65
66
  }
67
+ function enablePreloadMultiUse() {
68
+ for (const middleware of middlewares) {
69
+ middleware[import_preloading.ENABLE_MULTI_USE]?.();
70
+ }
71
+ }
72
+ function clearPreloadedData() {
73
+ for (const middleware of middlewares) {
74
+ middleware[import_preloading.CLEAR]?.();
75
+ }
76
+ }
66
77
  var defaultFetchHandler = (nextOptions) => {
67
78
  const { url, path, data, parse = true, ...remainingOptions } = nextOptions;
68
79
  let { body, headers } = nextOptions;
@@ -137,6 +148,11 @@ var apiFetch = (options) => {
137
148
  };
138
149
  apiFetch.use = registerMiddleware;
139
150
  apiFetch.setFetchHandler = setFetchHandler;
151
+ apiFetch.privateApis = {};
152
+ (0, import_lock_unlock.lock)(apiFetch.privateApis, {
153
+ enablePreloadMultiUse,
154
+ clearPreloadedData
155
+ });
140
156
  apiFetch.createNonceMiddleware = import_nonce.default;
141
157
  apiFetch.createPreloadingMiddleware = import_preloading.default;
142
158
  apiFetch.createRootURLMiddleware = import_root_url.default;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { __ } from '@wordpress/i18n';\n\n/**\n * Internal dependencies\n */\nimport createNonceMiddleware from './middlewares/nonce';\nimport createRootURLMiddleware from './middlewares/root-url';\nimport createPreloadingMiddleware from './middlewares/preloading';\nimport fetchAllMiddleware from './middlewares/fetch-all-middleware';\nimport namespaceEndpointMiddleware from './middlewares/namespace-endpoint';\nimport httpV1Middleware from './middlewares/http-v1';\nimport userLocaleMiddleware from './middlewares/user-locale';\nimport mediaUploadMiddleware from './middlewares/media-upload';\nimport createThemePreviewMiddleware from './middlewares/theme-preview';\nimport {\n\tparseResponseAndNormalizeError,\n\tparseAndThrowError,\n} from './utils/response';\nimport type {\n\tAPIFetchMiddleware,\n\tAPIFetchOptions,\n\tFetchHandler,\n} from './types';\n\n/**\n * Default set of header values which should be sent with every request unless\n * explicitly provided through apiFetch options.\n */\nconst DEFAULT_HEADERS: APIFetchOptions[ 'headers' ] = {\n\t// The backend uses the Accept header as a condition for considering an\n\t// incoming request as a REST request.\n\t//\n\t// See: https://core.trac.wordpress.org/ticket/44534\n\tAccept: 'application/json, */*;q=0.1',\n};\n\n/**\n * Default set of fetch option values which should be sent with every request\n * unless explicitly provided through apiFetch options.\n */\nconst DEFAULT_OPTIONS: APIFetchOptions = {\n\tcredentials: 'include',\n};\n\nconst middlewares: Array< APIFetchMiddleware > = [\n\tuserLocaleMiddleware,\n\tnamespaceEndpointMiddleware,\n\thttpV1Middleware,\n\tfetchAllMiddleware,\n];\n\n/**\n * Register a middleware\n *\n * @param middleware\n */\nfunction registerMiddleware( middleware: APIFetchMiddleware ) {\n\tmiddlewares.unshift( middleware );\n}\n\nconst defaultFetchHandler: FetchHandler = ( nextOptions ) => {\n\tconst { url, path, data, parse = true, ...remainingOptions } = nextOptions;\n\tlet { body, headers } = nextOptions;\n\n\t// Merge explicitly-provided headers with default values.\n\theaders = { ...DEFAULT_HEADERS, ...headers };\n\n\t// The `data` property is a shorthand for sending a JSON body.\n\tif ( data ) {\n\t\tbody = JSON.stringify( data );\n\t\theaders[ 'Content-Type' ] = 'application/json';\n\t}\n\n\tconst responsePromise = globalThis.fetch(\n\t\t// Fall back to explicitly passing `window.location` which is the behavior if `undefined` is passed.\n\t\turl || path || window.location.href,\n\t\t{\n\t\t\t...DEFAULT_OPTIONS,\n\t\t\t...remainingOptions,\n\t\t\tbody,\n\t\t\theaders,\n\t\t}\n\t);\n\n\treturn responsePromise.then(\n\t\t( response ) => {\n\t\t\t// If the response is not 2xx, still parse the response body as JSON\n\t\t\t// but throw the JSON as error.\n\t\t\tif ( ! response.ok ) {\n\t\t\t\treturn parseAndThrowError( response, parse );\n\t\t\t}\n\n\t\t\treturn parseResponseAndNormalizeError( response, parse );\n\t\t},\n\t\t( err ) => {\n\t\t\t// Re-throw AbortError for the users to handle it themselves.\n\t\t\tif ( err && err.name === 'AbortError' ) {\n\t\t\t\tthrow err;\n\t\t\t}\n\n\t\t\t// If the browser reports being offline, we'll just assume that\n\t\t\t// this is why the request failed.\n\t\t\tif ( ! globalThis.navigator.onLine ) {\n\t\t\t\tthrow {\n\t\t\t\t\tcode: 'offline_error',\n\t\t\t\t\tmessage: __(\n\t\t\t\t\t\t'Unable to connect. Please check your Internet connection.'\n\t\t\t\t\t),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Hard to diagnose further due to how Window.fetch reports errors.\n\t\t\tthrow {\n\t\t\t\tcode: 'fetch_error',\n\t\t\t\tmessage: __(\n\t\t\t\t\t'Could not get a valid response from the server.'\n\t\t\t\t),\n\t\t\t};\n\t\t}\n\t);\n};\n\nlet fetchHandler = defaultFetchHandler;\n\n/**\n * Defines a custom fetch handler for making the requests that will override\n * the default one using window.fetch\n *\n * @param newFetchHandler The new fetch handler\n */\nfunction setFetchHandler( newFetchHandler: FetchHandler ) {\n\tfetchHandler = newFetchHandler;\n}\n\nexport interface ApiFetch {\n\t< T, Parse extends boolean = true >(\n\t\toptions: APIFetchOptions< Parse >\n\t): Promise< Parse extends true ? T : Response >;\n\tnonceEndpoint?: string;\n\tnonceMiddleware?: ReturnType< typeof createNonceMiddleware >;\n\tuse: ( middleware: APIFetchMiddleware ) => void;\n\tsetFetchHandler: ( newFetchHandler: FetchHandler ) => void;\n\tcreateNonceMiddleware: typeof createNonceMiddleware;\n\tcreatePreloadingMiddleware: typeof createPreloadingMiddleware;\n\tcreateRootURLMiddleware: typeof createRootURLMiddleware;\n\tfetchAllMiddleware: typeof fetchAllMiddleware;\n\tmediaUploadMiddleware: typeof mediaUploadMiddleware;\n\tcreateThemePreviewMiddleware: typeof createThemePreviewMiddleware;\n}\n\n/**\n * Fetch\n *\n * @param options The options for the fetch.\n * @return A promise representing the request processed via the registered middlewares.\n */\nconst apiFetch: ApiFetch = ( options ) => {\n\t// creates a nested function chain that calls all middlewares and finally the `fetchHandler`,\n\t// converting `middlewares = [ m1, m2, m3 ]` into:\n\t// ```\n\t// opts1 => m1( opts1, opts2 => m2( opts2, opts3 => m3( opts3, fetchHandler ) ) );\n\t// ```\n\tconst enhancedHandler = middlewares.reduceRight< FetchHandler >(\n\t\t( next, middleware ) => {\n\t\t\treturn ( workingOptions ) => middleware( workingOptions, next );\n\t\t},\n\t\tfetchHandler\n\t);\n\n\treturn enhancedHandler( options ).catch( ( error ) => {\n\t\tif ( error.code !== 'rest_cookie_invalid_nonce' ) {\n\t\t\treturn Promise.reject( error );\n\t\t}\n\n\t\t// If the nonce is invalid, refresh it and try again.\n\t\treturn globalThis\n\t\t\t.fetch( apiFetch.nonceEndpoint! )\n\t\t\t.then( ( response ) => {\n\t\t\t\t// If the nonce refresh fails, it means we failed to recover from the original\n\t\t\t\t// `rest_cookie_invalid_nonce` error and that it's time to finally re-throw it.\n\t\t\t\tif ( ! response.ok ) {\n\t\t\t\t\treturn Promise.reject( error );\n\t\t\t\t}\n\n\t\t\t\treturn response.text();\n\t\t\t} )\n\t\t\t.then( ( text ) => {\n\t\t\t\tapiFetch.nonceMiddleware!.nonce = text;\n\t\t\t\treturn apiFetch( options );\n\t\t\t} );\n\t} );\n};\n\napiFetch.use = registerMiddleware;\napiFetch.setFetchHandler = setFetchHandler;\n\napiFetch.createNonceMiddleware = createNonceMiddleware;\napiFetch.createPreloadingMiddleware = createPreloadingMiddleware;\napiFetch.createRootURLMiddleware = createRootURLMiddleware;\napiFetch.fetchAllMiddleware = fetchAllMiddleware;\napiFetch.mediaUploadMiddleware = mediaUploadMiddleware;\napiFetch.createThemePreviewMiddleware = createThemePreviewMiddleware;\n\nexport default apiFetch;\nexport type * from './types';\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAAmB;AAKnB,mBAAkC;AAClC,sBAAoC;AACpC,wBAAuC;AACvC,kCAA+B;AAC/B,gCAAwC;AACxC,qBAA6B;AAC7B,yBAAiC;AACjC,0BAAkC;AAClC,2BAAyC;AACzC,sBAGO;AAWP,IAAM,kBAAgD;AAAA;AAAA;AAAA;AAAA;AAAA,EAKrD,QAAQ;AACT;AAMA,IAAM,kBAAmC;AAAA,EACxC,aAAa;AACd;AAEA,IAAM,cAA2C;AAAA,EAChD,mBAAAA;AAAA,EACA,0BAAAC;AAAA,EACA,eAAAC;AAAA,EACA,4BAAAC;AACD;AAOA,SAAS,mBAAoB,YAAiC;AAC7D,cAAY,QAAS,UAAW;AACjC;AAEA,IAAM,sBAAoC,CAAE,gBAAiB;AAC5D,QAAM,EAAE,KAAK,MAAM,MAAM,QAAQ,MAAM,GAAG,iBAAiB,IAAI;AAC/D,MAAI,EAAE,MAAM,QAAQ,IAAI;AAGxB,YAAU,EAAE,GAAG,iBAAiB,GAAG,QAAQ;AAG3C,MAAK,MAAO;AACX,WAAO,KAAK,UAAW,IAAK;AAC5B,YAAS,cAAe,IAAI;AAAA,EAC7B;AAEA,QAAM,kBAAkB,WAAW;AAAA;AAAA,IAElC,OAAO,QAAQ,OAAO,SAAS;AAAA,IAC/B;AAAA,MACC,GAAG;AAAA,MACH,GAAG;AAAA,MACH;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAEA,SAAO,gBAAgB;AAAA,IACtB,CAAE,aAAc;AAGf,UAAK,CAAE,SAAS,IAAK;AACpB,mBAAO,oCAAoB,UAAU,KAAM;AAAA,MAC5C;AAEA,iBAAO,gDAAgC,UAAU,KAAM;AAAA,IACxD;AAAA,IACA,CAAE,QAAS;AAEV,UAAK,OAAO,IAAI,SAAS,cAAe;AACvC,cAAM;AAAA,MACP;AAIA,UAAK,CAAE,WAAW,UAAU,QAAS;AACpC,cAAM;AAAA,UACL,MAAM;AAAA,UACN,aAAS;AAAA,YACR;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAGA,YAAM;AAAA,QACL,MAAM;AAAA,QACN,aAAS;AAAA,UACR;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACD;AAEA,IAAI,eAAe;AAQnB,SAAS,gBAAiB,iBAAgC;AACzD,iBAAe;AAChB;AAwBA,IAAM,WAAqB,CAAE,YAAa;AAMzC,QAAM,kBAAkB,YAAY;AAAA,IACnC,CAAE,MAAM,eAAgB;AACvB,aAAO,CAAE,mBAAoB,WAAY,gBAAgB,IAAK;AAAA,IAC/D;AAAA,IACA;AAAA,EACD;AAEA,SAAO,gBAAiB,OAAQ,EAAE,MAAO,CAAE,UAAW;AACrD,QAAK,MAAM,SAAS,6BAA8B;AACjD,aAAO,QAAQ,OAAQ,KAAM;AAAA,IAC9B;AAGA,WAAO,WACL,MAAO,SAAS,aAAe,EAC/B,KAAM,CAAE,aAAc;AAGtB,UAAK,CAAE,SAAS,IAAK;AACpB,eAAO,QAAQ,OAAQ,KAAM;AAAA,MAC9B;AAEA,aAAO,SAAS,KAAK;AAAA,IACtB,CAAE,EACD,KAAM,CAAE,SAAU;AAClB,eAAS,gBAAiB,QAAQ;AAClC,aAAO,SAAU,OAAQ;AAAA,IAC1B,CAAE;AAAA,EACJ,CAAE;AACH;AAEA,SAAS,MAAM;AACf,SAAS,kBAAkB;AAE3B,SAAS,wBAAwB,aAAAC;AACjC,SAAS,6BAA6B,kBAAAC;AACtC,SAAS,0BAA0B,gBAAAC;AACnC,SAAS,qBAAqB,4BAAAH;AAC9B,SAAS,wBAAwB,oBAAAI;AACjC,SAAS,+BAA+B,qBAAAC;AAExC,IAAO,gBAAQ;",
6
- "names": ["userLocaleMiddleware", "namespaceEndpointMiddleware", "httpV1Middleware", "fetchAllMiddleware", "createNonceMiddleware", "createPreloadingMiddleware", "createRootURLMiddleware", "mediaUploadMiddleware", "createThemePreviewMiddleware"]
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { __ } from '@wordpress/i18n';\n\n/**\n * Internal dependencies\n */\nimport { lock } from './lock-unlock';\nimport createNonceMiddleware from './middlewares/nonce';\nimport createRootURLMiddleware from './middlewares/root-url';\nimport createPreloadingMiddleware, {\n\tCLEAR as PRELOADING_CLEAR,\n\tENABLE_MULTI_USE as PRELOADING_ENABLE_MULTI_USE,\n} from './middlewares/preloading';\nimport fetchAllMiddleware from './middlewares/fetch-all-middleware';\nimport namespaceEndpointMiddleware from './middlewares/namespace-endpoint';\nimport httpV1Middleware from './middlewares/http-v1';\nimport userLocaleMiddleware from './middlewares/user-locale';\nimport mediaUploadMiddleware from './middlewares/media-upload';\nimport createThemePreviewMiddleware from './middlewares/theme-preview';\nimport {\n\tparseResponseAndNormalizeError,\n\tparseAndThrowError,\n} from './utils/response';\nimport type {\n\tAPIFetchMiddleware,\n\tAPIFetchOptions,\n\tFetchHandler,\n} from './types';\n\n/**\n * Default set of header values which should be sent with every request unless\n * explicitly provided through apiFetch options.\n */\nconst DEFAULT_HEADERS: APIFetchOptions[ 'headers' ] = {\n\t// The backend uses the Accept header as a condition for considering an\n\t// incoming request as a REST request.\n\t//\n\t// See: https://core.trac.wordpress.org/ticket/44534\n\tAccept: 'application/json, */*;q=0.1',\n};\n\n/**\n * Default set of fetch option values which should be sent with every request\n * unless explicitly provided through apiFetch options.\n */\nconst DEFAULT_OPTIONS: APIFetchOptions = {\n\tcredentials: 'include',\n};\n\nconst middlewares: Array< APIFetchMiddleware > = [\n\tuserLocaleMiddleware,\n\tnamespaceEndpointMiddleware,\n\thttpV1Middleware,\n\tfetchAllMiddleware,\n];\n\n/**\n * Register a middleware\n *\n * @param middleware\n */\nfunction registerMiddleware( middleware: APIFetchMiddleware ) {\n\tmiddlewares.unshift( middleware );\n}\n\nfunction enablePreloadMultiUse() {\n\tfor ( const middleware of middlewares ) {\n\t\t( middleware as any )[ PRELOADING_ENABLE_MULTI_USE ]?.();\n\t}\n}\n\nfunction clearPreloadedData() {\n\tfor ( const middleware of middlewares ) {\n\t\t( middleware as any )[ PRELOADING_CLEAR ]?.();\n\t}\n}\n\nconst defaultFetchHandler: FetchHandler = ( nextOptions ) => {\n\tconst { url, path, data, parse = true, ...remainingOptions } = nextOptions;\n\tlet { body, headers } = nextOptions;\n\n\t// Merge explicitly-provided headers with default values.\n\theaders = { ...DEFAULT_HEADERS, ...headers };\n\n\t// The `data` property is a shorthand for sending a JSON body.\n\tif ( data ) {\n\t\tbody = JSON.stringify( data );\n\t\theaders[ 'Content-Type' ] = 'application/json';\n\t}\n\n\tconst responsePromise = globalThis.fetch(\n\t\t// Fall back to explicitly passing `window.location` which is the behavior if `undefined` is passed.\n\t\turl || path || window.location.href,\n\t\t{\n\t\t\t...DEFAULT_OPTIONS,\n\t\t\t...remainingOptions,\n\t\t\tbody,\n\t\t\theaders,\n\t\t}\n\t);\n\n\treturn responsePromise.then(\n\t\t( response ) => {\n\t\t\t// If the response is not 2xx, still parse the response body as JSON\n\t\t\t// but throw the JSON as error.\n\t\t\tif ( ! response.ok ) {\n\t\t\t\treturn parseAndThrowError( response, parse );\n\t\t\t}\n\n\t\t\treturn parseResponseAndNormalizeError( response, parse );\n\t\t},\n\t\t( err ) => {\n\t\t\t// Re-throw AbortError for the users to handle it themselves.\n\t\t\tif ( err && err.name === 'AbortError' ) {\n\t\t\t\tthrow err;\n\t\t\t}\n\n\t\t\t// If the browser reports being offline, we'll just assume that\n\t\t\t// this is why the request failed.\n\t\t\tif ( ! globalThis.navigator.onLine ) {\n\t\t\t\tthrow {\n\t\t\t\t\tcode: 'offline_error',\n\t\t\t\t\tmessage: __(\n\t\t\t\t\t\t'Unable to connect. Please check your Internet connection.'\n\t\t\t\t\t),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Hard to diagnose further due to how Window.fetch reports errors.\n\t\t\tthrow {\n\t\t\t\tcode: 'fetch_error',\n\t\t\t\tmessage: __(\n\t\t\t\t\t'Could not get a valid response from the server.'\n\t\t\t\t),\n\t\t\t};\n\t\t}\n\t);\n};\n\nlet fetchHandler = defaultFetchHandler;\n\n/**\n * Defines a custom fetch handler for making the requests that will override\n * the default one using window.fetch\n *\n * @param newFetchHandler The new fetch handler\n */\nfunction setFetchHandler( newFetchHandler: FetchHandler ) {\n\tfetchHandler = newFetchHandler;\n}\n\nexport interface ApiFetch {\n\t< T, Parse extends boolean = true >(\n\t\toptions: APIFetchOptions< Parse >\n\t): Promise< Parse extends true ? T : Response >;\n\tnonceEndpoint?: string;\n\tnonceMiddleware?: ReturnType< typeof createNonceMiddleware >;\n\tuse: ( middleware: APIFetchMiddleware ) => void;\n\tsetFetchHandler: ( newFetchHandler: FetchHandler ) => void;\n\tcreateNonceMiddleware: typeof createNonceMiddleware;\n\tcreatePreloadingMiddleware: typeof createPreloadingMiddleware;\n\tcreateRootURLMiddleware: typeof createRootURLMiddleware;\n\tfetchAllMiddleware: typeof fetchAllMiddleware;\n\tmediaUploadMiddleware: typeof mediaUploadMiddleware;\n\tcreateThemePreviewMiddleware: typeof createThemePreviewMiddleware;\n\tprivateApis: object;\n}\n\n/**\n * Fetch\n *\n * @param options The options for the fetch.\n * @return A promise representing the request processed via the registered middlewares.\n */\nconst apiFetch: ApiFetch = ( options ) => {\n\t// creates a nested function chain that calls all middlewares and finally the `fetchHandler`,\n\t// converting `middlewares = [ m1, m2, m3 ]` into:\n\t// ```\n\t// opts1 => m1( opts1, opts2 => m2( opts2, opts3 => m3( opts3, fetchHandler ) ) );\n\t// ```\n\tconst enhancedHandler = middlewares.reduceRight< FetchHandler >(\n\t\t( next, middleware ) => {\n\t\t\treturn ( workingOptions ) => middleware( workingOptions, next );\n\t\t},\n\t\tfetchHandler\n\t);\n\n\treturn enhancedHandler( options ).catch( ( error ) => {\n\t\tif ( error.code !== 'rest_cookie_invalid_nonce' ) {\n\t\t\treturn Promise.reject( error );\n\t\t}\n\n\t\t// If the nonce is invalid, refresh it and try again.\n\t\treturn globalThis\n\t\t\t.fetch( apiFetch.nonceEndpoint! )\n\t\t\t.then( ( response ) => {\n\t\t\t\t// If the nonce refresh fails, it means we failed to recover from the original\n\t\t\t\t// `rest_cookie_invalid_nonce` error and that it's time to finally re-throw it.\n\t\t\t\tif ( ! response.ok ) {\n\t\t\t\t\treturn Promise.reject( error );\n\t\t\t\t}\n\n\t\t\t\treturn response.text();\n\t\t\t} )\n\t\t\t.then( ( text ) => {\n\t\t\t\tapiFetch.nonceMiddleware!.nonce = text;\n\t\t\t\treturn apiFetch( options );\n\t\t\t} );\n\t} );\n};\n\napiFetch.use = registerMiddleware;\napiFetch.setFetchHandler = setFetchHandler;\n\n// Attached to the function (rather than a named export) because\n// `wpScriptDefaultExport: true` flattens this module to its default\n// export \u2014 `wp.apiFetch` is the function itself, so anything that\n// needs to be reachable from a consumer's `wp.apiFetch.X` lookup has\n// to live on the function.\napiFetch.privateApis = {};\nlock( apiFetch.privateApis, {\n\tenablePreloadMultiUse,\n\tclearPreloadedData,\n} );\n\napiFetch.createNonceMiddleware = createNonceMiddleware;\napiFetch.createPreloadingMiddleware = createPreloadingMiddleware;\napiFetch.createRootURLMiddleware = createRootURLMiddleware;\napiFetch.fetchAllMiddleware = fetchAllMiddleware;\napiFetch.mediaUploadMiddleware = mediaUploadMiddleware;\napiFetch.createThemePreviewMiddleware = createThemePreviewMiddleware;\n\nexport default apiFetch;\nexport type * from './types';\n"],
5
+ "mappings": "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",
6
+ "names": ["userLocaleMiddleware", "namespaceEndpointMiddleware", "httpV1Middleware", "fetchAllMiddleware", "PRELOADING_ENABLE_MULTI_USE", "PRELOADING_CLEAR", "createNonceMiddleware", "createPreloadingMiddleware", "createRootURLMiddleware", "mediaUploadMiddleware", "createThemePreviewMiddleware"]
7
7
  }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // packages/api-fetch/src/lock-unlock.ts
21
+ var lock_unlock_exports = {};
22
+ __export(lock_unlock_exports, {
23
+ lock: () => lock,
24
+ unlock: () => unlock
25
+ });
26
+ module.exports = __toCommonJS(lock_unlock_exports);
27
+ var import_private_apis = require("@wordpress/private-apis");
28
+ var { lock, unlock } = (0, import_private_apis.__dangerousOptInToUnstableAPIsOnlyForCoreModules)(
29
+ "I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.",
30
+ "@wordpress/api-fetch"
31
+ );
32
+ // Annotate the CommonJS export names for ESM import in node:
33
+ 0 && (module.exports = {
34
+ lock,
35
+ unlock
36
+ });
37
+ //# sourceMappingURL=lock-unlock.cjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/lock-unlock.ts"],
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/private-apis';\n\nexport const { lock, unlock } =\n\t__dangerousOptInToUnstableAPIsOnlyForCoreModules(\n\t\t'I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.',\n\t\t'@wordpress/api-fetch'\n\t);\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,0BAAiE;AAE1D,IAAM,EAAE,MAAM,OAAO,QAC3B;AAAA,EACC;AAAA,EACA;AACD;",
6
+ "names": []
7
+ }
@@ -20,18 +20,25 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // packages/api-fetch/src/middlewares/preloading.ts
21
21
  var preloading_exports = {};
22
22
  __export(preloading_exports, {
23
+ CLEAR: () => CLEAR,
24
+ ENABLE_MULTI_USE: () => ENABLE_MULTI_USE,
23
25
  default: () => preloading_default
24
26
  });
25
27
  module.exports = __toCommonJS(preloading_exports);
26
28
  var import_url = require("@wordpress/url");
29
+ var ENABLE_MULTI_USE = /* @__PURE__ */ Symbol("preloadingEnableMultiUse");
30
+ var CLEAR = /* @__PURE__ */ Symbol("preloadingClear");
27
31
  function createPreloadingMiddleware(preloadedData) {
28
- const cache = Object.fromEntries(
32
+ const { OPTIONS = {}, ...GET } = Object.fromEntries(
29
33
  Object.entries(preloadedData).map(([path, data]) => [
30
34
  (0, import_url.normalizePath)(path),
31
35
  data
32
36
  ])
33
37
  );
34
- return (options, next) => {
38
+ const unusedGet = new Set(Object.keys(GET));
39
+ const unusedOptions = new Set(Object.keys(OPTIONS));
40
+ let multiUse = false;
41
+ const middleware = (options, next) => {
35
42
  const { parse = true } = options;
36
43
  let rawPath = options.path;
37
44
  if (!rawPath && options.url) {
@@ -47,17 +54,49 @@ function createPreloadingMiddleware(preloadedData) {
47
54
  }
48
55
  const method = options.method || "GET";
49
56
  const path = (0, import_url.normalizePath)(rawPath);
50
- if ("GET" === method && cache[path]) {
51
- const cacheData = cache[path];
52
- delete cache[path];
53
- return prepareResponse(cacheData, !!parse);
54
- } else if ("OPTIONS" === method && cache[method] && cache[method][path]) {
55
- const cacheData = cache[method][path];
56
- delete cache[method][path];
57
- return prepareResponse(cacheData, !!parse);
57
+ if ("GET" === method && GET[path]) {
58
+ const data = GET[path];
59
+ if (!multiUse) {
60
+ delete GET[path];
61
+ }
62
+ unusedGet.delete(path);
63
+ return prepareResponse(data, !!parse);
64
+ } else if ("OPTIONS" === method && OPTIONS[path]) {
65
+ const data = OPTIONS[path];
66
+ if (!multiUse) {
67
+ delete OPTIONS[path];
68
+ }
69
+ unusedOptions.delete(path);
70
+ return prepareResponse(data, !!parse);
58
71
  }
59
72
  return next(options);
60
73
  };
74
+ middleware[ENABLE_MULTI_USE] = () => {
75
+ multiUse = true;
76
+ };
77
+ middleware[CLEAR] = () => {
78
+ const tags = [
79
+ ...Array.from(unusedGet, (p) => `GET ${p}`),
80
+ ...Array.from(unusedOptions, (p) => `OPTIONS ${p}`)
81
+ ];
82
+ if (tags.length) {
83
+ console.warn(
84
+ "[api-fetch][preload] Some preloads were never consumed:",
85
+ tags
86
+ );
87
+ } else {
88
+ console.log("[api-fetch][preload] All preloads consumed.");
89
+ }
90
+ unusedGet.clear();
91
+ unusedOptions.clear();
92
+ for (const key of Object.keys(GET)) {
93
+ delete GET[key];
94
+ }
95
+ for (const key of Object.keys(OPTIONS)) {
96
+ delete OPTIONS[key];
97
+ }
98
+ };
99
+ return middleware;
61
100
  }
62
101
  function prepareResponse(responseData, parse) {
63
102
  if (parse) {
@@ -92,4 +131,9 @@ function prepareResponse(responseData, parse) {
92
131
  }
93
132
  }
94
133
  var preloading_default = createPreloadingMiddleware;
134
+ // Annotate the CommonJS export names for ESM import in node:
135
+ 0 && (module.exports = {
136
+ CLEAR,
137
+ ENABLE_MULTI_USE
138
+ });
95
139
  //# sourceMappingURL=preloading.cjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/middlewares/preloading.ts"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { addQueryArgs, getQueryArgs, normalizePath } from '@wordpress/url';\n\n/**\n * Internal dependencies\n */\nimport type { APIFetchMiddleware } from '../types';\n\n/**\n * @param preloadedData\n * @return Preloading middleware.\n */\nfunction createPreloadingMiddleware(\n\tpreloadedData: Record< string, any >\n): APIFetchMiddleware {\n\tconst cache = Object.fromEntries(\n\t\tObject.entries( preloadedData ).map( ( [ path, data ] ) => [\n\t\t\tnormalizePath( path ),\n\t\t\tdata,\n\t\t] )\n\t);\n\n\treturn ( options, next ) => {\n\t\tconst { parse = true } = options;\n\t\tlet rawPath = options.path;\n\t\tif ( ! rawPath && options.url ) {\n\t\t\tconst { rest_route: pathFromQuery, ...queryArgs } = getQueryArgs(\n\t\t\t\toptions.url\n\t\t\t);\n\n\t\t\tif ( typeof pathFromQuery === 'string' ) {\n\t\t\t\trawPath = addQueryArgs( pathFromQuery, queryArgs );\n\t\t\t}\n\t\t}\n\n\t\tif ( typeof rawPath !== 'string' ) {\n\t\t\treturn next( options );\n\t\t}\n\n\t\tconst method = options.method || 'GET';\n\t\tconst path = normalizePath( rawPath );\n\n\t\tif ( 'GET' === method && cache[ path ] ) {\n\t\t\tconst cacheData = cache[ path ];\n\n\t\t\t// Unsetting the cache key ensures that the data is only used a single time.\n\t\t\tdelete cache[ path ];\n\n\t\t\treturn prepareResponse( cacheData, !! parse );\n\t\t} else if (\n\t\t\t'OPTIONS' === method &&\n\t\t\tcache[ method ] &&\n\t\t\tcache[ method ][ path ]\n\t\t) {\n\t\t\tconst cacheData = cache[ method ][ path ];\n\n\t\t\t// Unsetting the cache key ensures that the data is only used a single time.\n\t\t\tdelete cache[ method ][ path ];\n\n\t\t\treturn prepareResponse( cacheData, !! parse );\n\t\t}\n\n\t\treturn next( options );\n\t};\n}\n\n/**\n * This is a helper function that sends a success response.\n *\n * @param responseData\n * @param parse\n * @return Promise with the response.\n */\nfunction prepareResponse(\n\tresponseData: Record< string, any >,\n\tparse: boolean\n) {\n\tif ( parse ) {\n\t\treturn Promise.resolve( responseData.body );\n\t}\n\n\ttry {\n\t\treturn Promise.resolve(\n\t\t\tnew window.Response( JSON.stringify( responseData.body ), {\n\t\t\t\tstatus: 200,\n\t\t\t\tstatusText: 'OK',\n\t\t\t\theaders: responseData.headers,\n\t\t\t} )\n\t\t);\n\t} catch {\n\t\t// See: https://github.com/WordPress/gutenberg/issues/67358#issuecomment-2621163926.\n\t\tObject.entries(\n\t\t\tresponseData.headers as Record< string, string >\n\t\t).forEach( ( [ key, value ] ) => {\n\t\t\tif ( key.toLowerCase() === 'link' ) {\n\t\t\t\tresponseData.headers[ key ] = value.replace(\n\t\t\t\t\t/<([^>]+)>/,\n\t\t\t\t\t( _, url ) => `<${ encodeURI( url ) }>`\n\t\t\t\t);\n\t\t\t}\n\t\t} );\n\n\t\treturn Promise.resolve(\n\t\t\tparse\n\t\t\t\t? responseData.body\n\t\t\t\t: new window.Response( JSON.stringify( responseData.body ), {\n\t\t\t\t\t\tstatus: 200,\n\t\t\t\t\t\tstatusText: 'OK',\n\t\t\t\t\t\theaders: responseData.headers,\n\t\t\t\t } )\n\t\t);\n\t}\n}\n\nexport default createPreloadingMiddleware;\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,iBAA0D;AAW1D,SAAS,2BACR,eACqB;AACrB,QAAM,QAAQ,OAAO;AAAA,IACpB,OAAO,QAAS,aAAc,EAAE,IAAK,CAAE,CAAE,MAAM,IAAK,MAAO;AAAA,UAC1D,0BAAe,IAAK;AAAA,MACpB;AAAA,IACD,CAAE;AAAA,EACH;AAEA,SAAO,CAAE,SAAS,SAAU;AAC3B,UAAM,EAAE,QAAQ,KAAK,IAAI;AACzB,QAAI,UAAU,QAAQ;AACtB,QAAK,CAAE,WAAW,QAAQ,KAAM;AAC/B,YAAM,EAAE,YAAY,eAAe,GAAG,UAAU,QAAI;AAAA,QACnD,QAAQ;AAAA,MACT;AAEA,UAAK,OAAO,kBAAkB,UAAW;AACxC,sBAAU,yBAAc,eAAe,SAAU;AAAA,MAClD;AAAA,IACD;AAEA,QAAK,OAAO,YAAY,UAAW;AAClC,aAAO,KAAM,OAAQ;AAAA,IACtB;AAEA,UAAM,SAAS,QAAQ,UAAU;AACjC,UAAM,WAAO,0BAAe,OAAQ;AAEpC,QAAK,UAAU,UAAU,MAAO,IAAK,GAAI;AACxC,YAAM,YAAY,MAAO,IAAK;AAG9B,aAAO,MAAO,IAAK;AAEnB,aAAO,gBAAiB,WAAW,CAAC,CAAE,KAAM;AAAA,IAC7C,WACC,cAAc,UACd,MAAO,MAAO,KACd,MAAO,MAAO,EAAG,IAAK,GACrB;AACD,YAAM,YAAY,MAAO,MAAO,EAAG,IAAK;AAGxC,aAAO,MAAO,MAAO,EAAG,IAAK;AAE7B,aAAO,gBAAiB,WAAW,CAAC,CAAE,KAAM;AAAA,IAC7C;AAEA,WAAO,KAAM,OAAQ;AAAA,EACtB;AACD;AASA,SAAS,gBACR,cACA,OACC;AACD,MAAK,OAAQ;AACZ,WAAO,QAAQ,QAAS,aAAa,IAAK;AAAA,EAC3C;AAEA,MAAI;AACH,WAAO,QAAQ;AAAA,MACd,IAAI,OAAO,SAAU,KAAK,UAAW,aAAa,IAAK,GAAG;AAAA,QACzD,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,SAAS,aAAa;AAAA,MACvB,CAAE;AAAA,IACH;AAAA,EACD,QAAQ;AAEP,WAAO;AAAA,MACN,aAAa;AAAA,IACd,EAAE,QAAS,CAAE,CAAE,KAAK,KAAM,MAAO;AAChC,UAAK,IAAI,YAAY,MAAM,QAAS;AACnC,qBAAa,QAAS,GAAI,IAAI,MAAM;AAAA,UACnC;AAAA,UACA,CAAE,GAAG,QAAS,IAAK,UAAW,GAAI,CAAE;AAAA,QACrC;AAAA,MACD;AAAA,IACD,CAAE;AAEF,WAAO,QAAQ;AAAA,MACd,QACG,aAAa,OACb,IAAI,OAAO,SAAU,KAAK,UAAW,aAAa,IAAK,GAAG;AAAA,QAC1D,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,SAAS,aAAa;AAAA,MACtB,CAAE;AAAA,IACN;AAAA,EACD;AACD;AAEA,IAAO,qBAAQ;",
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { addQueryArgs, getQueryArgs, normalizePath } from '@wordpress/url';\n\n/**\n * Internal dependencies\n */\nimport type { APIFetchMiddleware } from '../types';\n\nexport const ENABLE_MULTI_USE = Symbol( 'preloadingEnableMultiUse' );\nexport const CLEAR = Symbol( 'preloadingClear' );\n\n/**\n * @param preloadedData\n * @return Preloading middleware.\n */\nfunction createPreloadingMiddleware(\n\tpreloadedData: Record< string, any >\n): APIFetchMiddleware {\n\tconst { OPTIONS = {}, ...GET } = Object.fromEntries(\n\t\tObject.entries( preloadedData ).map( ( [ path, data ] ) => [\n\t\t\tnormalizePath( path ),\n\t\t\tdata,\n\t\t] )\n\t) as Record< string, any > & { OPTIONS?: Record< string, any > };\n\n\t// Preload entries that haven't been served yet.\n\tconst unusedGet = new Set< string >( Object.keys( GET ) );\n\tconst unusedOptions = new Set< string >( Object.keys( OPTIONS ) );\n\n\tlet multiUse = false;\n\n\tconst middleware: APIFetchMiddleware = ( options, next ) => {\n\t\tconst { parse = true } = options;\n\t\tlet rawPath = options.path;\n\t\tif ( ! rawPath && options.url ) {\n\t\t\tconst { rest_route: pathFromQuery, ...queryArgs } = getQueryArgs(\n\t\t\t\toptions.url\n\t\t\t);\n\n\t\t\tif ( typeof pathFromQuery === 'string' ) {\n\t\t\t\trawPath = addQueryArgs( pathFromQuery, queryArgs );\n\t\t\t}\n\t\t}\n\n\t\tif ( typeof rawPath !== 'string' ) {\n\t\t\treturn next( options );\n\t\t}\n\n\t\tconst method = options.method || 'GET';\n\t\tconst path = normalizePath( rawPath );\n\n\t\tif ( 'GET' === method && GET[ path ] ) {\n\t\t\tconst data = GET[ path ];\n\t\t\tif ( ! multiUse ) {\n\t\t\t\tdelete GET[ path ];\n\t\t\t}\n\t\t\tunusedGet.delete( path );\n\t\t\treturn prepareResponse( data, !! parse );\n\t\t} else if ( 'OPTIONS' === method && OPTIONS[ path ] ) {\n\t\t\tconst data = OPTIONS[ path ];\n\t\t\tif ( ! multiUse ) {\n\t\t\t\tdelete OPTIONS[ path ];\n\t\t\t}\n\t\t\tunusedOptions.delete( path );\n\t\t\treturn prepareResponse( data, !! parse );\n\t\t}\n\n\t\treturn next( options );\n\t};\n\n\t( middleware as any )[ ENABLE_MULTI_USE ] = () => {\n\t\tmultiUse = true;\n\t};\n\n\t( middleware as any )[ CLEAR ] = (): void => {\n\t\tconst tags = [\n\t\t\t...Array.from( unusedGet, ( p ) => `GET ${ p }` ),\n\t\t\t...Array.from( unusedOptions, ( p ) => `OPTIONS ${ p }` ),\n\t\t];\n\t\tif ( tags.length ) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(\n\t\t\t\t'[api-fetch][preload] Some preloads were never consumed:',\n\t\t\t\ttags\n\t\t\t);\n\t\t} else {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.log( '[api-fetch][preload] All preloads consumed.' );\n\t\t}\n\t\tunusedGet.clear();\n\t\tunusedOptions.clear();\n\t\tfor ( const key of Object.keys( GET ) ) {\n\t\t\tdelete GET[ key ];\n\t\t}\n\t\tfor ( const key of Object.keys( OPTIONS ) ) {\n\t\t\tdelete OPTIONS[ key ];\n\t\t}\n\t};\n\n\treturn middleware;\n}\n\n/**\n * This is a helper function that sends a success response.\n *\n * @param responseData\n * @param parse\n * @return Promise with the response.\n */\nfunction prepareResponse(\n\tresponseData: Record< string, any >,\n\tparse: boolean\n) {\n\tif ( parse ) {\n\t\treturn Promise.resolve( responseData.body );\n\t}\n\n\ttry {\n\t\treturn Promise.resolve(\n\t\t\tnew window.Response( JSON.stringify( responseData.body ), {\n\t\t\t\tstatus: 200,\n\t\t\t\tstatusText: 'OK',\n\t\t\t\theaders: responseData.headers,\n\t\t\t} )\n\t\t);\n\t} catch {\n\t\t// See: https://github.com/WordPress/gutenberg/issues/67358#issuecomment-2621163926.\n\t\tObject.entries(\n\t\t\tresponseData.headers as Record< string, string >\n\t\t).forEach( ( [ key, value ] ) => {\n\t\t\tif ( key.toLowerCase() === 'link' ) {\n\t\t\t\tresponseData.headers[ key ] = value.replace(\n\t\t\t\t\t/<([^>]+)>/,\n\t\t\t\t\t( _, url ) => `<${ encodeURI( url ) }>`\n\t\t\t\t);\n\t\t\t}\n\t\t} );\n\n\t\treturn Promise.resolve(\n\t\t\tparse\n\t\t\t\t? responseData.body\n\t\t\t\t: new window.Response( JSON.stringify( responseData.body ), {\n\t\t\t\t\t\tstatus: 200,\n\t\t\t\t\t\tstatusText: 'OK',\n\t\t\t\t\t\theaders: responseData.headers,\n\t\t\t\t } )\n\t\t);\n\t}\n}\n\nexport default createPreloadingMiddleware;\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,8 +1,12 @@
1
1
  // packages/api-fetch/src/index.ts
2
2
  import { __ } from "@wordpress/i18n";
3
+ import { lock } from "./lock-unlock.mjs";
3
4
  import createNonceMiddleware from "./middlewares/nonce.mjs";
4
5
  import createRootURLMiddleware from "./middlewares/root-url.mjs";
5
- import createPreloadingMiddleware from "./middlewares/preloading.mjs";
6
+ import createPreloadingMiddleware, {
7
+ CLEAR as PRELOADING_CLEAR,
8
+ ENABLE_MULTI_USE as PRELOADING_ENABLE_MULTI_USE
9
+ } from "./middlewares/preloading.mjs";
6
10
  import fetchAllMiddleware from "./middlewares/fetch-all-middleware.mjs";
7
11
  import namespaceEndpointMiddleware from "./middlewares/namespace-endpoint.mjs";
8
12
  import httpV1Middleware from "./middlewares/http-v1.mjs";
@@ -32,6 +36,16 @@ var middlewares = [
32
36
  function registerMiddleware(middleware) {
33
37
  middlewares.unshift(middleware);
34
38
  }
39
+ function enablePreloadMultiUse() {
40
+ for (const middleware of middlewares) {
41
+ middleware[PRELOADING_ENABLE_MULTI_USE]?.();
42
+ }
43
+ }
44
+ function clearPreloadedData() {
45
+ for (const middleware of middlewares) {
46
+ middleware[PRELOADING_CLEAR]?.();
47
+ }
48
+ }
35
49
  var defaultFetchHandler = (nextOptions) => {
36
50
  const { url, path, data, parse = true, ...remainingOptions } = nextOptions;
37
51
  let { body, headers } = nextOptions;
@@ -106,6 +120,11 @@ var apiFetch = (options) => {
106
120
  };
107
121
  apiFetch.use = registerMiddleware;
108
122
  apiFetch.setFetchHandler = setFetchHandler;
123
+ apiFetch.privateApis = {};
124
+ lock(apiFetch.privateApis, {
125
+ enablePreloadMultiUse,
126
+ clearPreloadedData
127
+ });
109
128
  apiFetch.createNonceMiddleware = createNonceMiddleware;
110
129
  apiFetch.createPreloadingMiddleware = createPreloadingMiddleware;
111
130
  apiFetch.createRootURLMiddleware = createRootURLMiddleware;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { __ } from '@wordpress/i18n';\n\n/**\n * Internal dependencies\n */\nimport createNonceMiddleware from './middlewares/nonce';\nimport createRootURLMiddleware from './middlewares/root-url';\nimport createPreloadingMiddleware from './middlewares/preloading';\nimport fetchAllMiddleware from './middlewares/fetch-all-middleware';\nimport namespaceEndpointMiddleware from './middlewares/namespace-endpoint';\nimport httpV1Middleware from './middlewares/http-v1';\nimport userLocaleMiddleware from './middlewares/user-locale';\nimport mediaUploadMiddleware from './middlewares/media-upload';\nimport createThemePreviewMiddleware from './middlewares/theme-preview';\nimport {\n\tparseResponseAndNormalizeError,\n\tparseAndThrowError,\n} from './utils/response';\nimport type {\n\tAPIFetchMiddleware,\n\tAPIFetchOptions,\n\tFetchHandler,\n} from './types';\n\n/**\n * Default set of header values which should be sent with every request unless\n * explicitly provided through apiFetch options.\n */\nconst DEFAULT_HEADERS: APIFetchOptions[ 'headers' ] = {\n\t// The backend uses the Accept header as a condition for considering an\n\t// incoming request as a REST request.\n\t//\n\t// See: https://core.trac.wordpress.org/ticket/44534\n\tAccept: 'application/json, */*;q=0.1',\n};\n\n/**\n * Default set of fetch option values which should be sent with every request\n * unless explicitly provided through apiFetch options.\n */\nconst DEFAULT_OPTIONS: APIFetchOptions = {\n\tcredentials: 'include',\n};\n\nconst middlewares: Array< APIFetchMiddleware > = [\n\tuserLocaleMiddleware,\n\tnamespaceEndpointMiddleware,\n\thttpV1Middleware,\n\tfetchAllMiddleware,\n];\n\n/**\n * Register a middleware\n *\n * @param middleware\n */\nfunction registerMiddleware( middleware: APIFetchMiddleware ) {\n\tmiddlewares.unshift( middleware );\n}\n\nconst defaultFetchHandler: FetchHandler = ( nextOptions ) => {\n\tconst { url, path, data, parse = true, ...remainingOptions } = nextOptions;\n\tlet { body, headers } = nextOptions;\n\n\t// Merge explicitly-provided headers with default values.\n\theaders = { ...DEFAULT_HEADERS, ...headers };\n\n\t// The `data` property is a shorthand for sending a JSON body.\n\tif ( data ) {\n\t\tbody = JSON.stringify( data );\n\t\theaders[ 'Content-Type' ] = 'application/json';\n\t}\n\n\tconst responsePromise = globalThis.fetch(\n\t\t// Fall back to explicitly passing `window.location` which is the behavior if `undefined` is passed.\n\t\turl || path || window.location.href,\n\t\t{\n\t\t\t...DEFAULT_OPTIONS,\n\t\t\t...remainingOptions,\n\t\t\tbody,\n\t\t\theaders,\n\t\t}\n\t);\n\n\treturn responsePromise.then(\n\t\t( response ) => {\n\t\t\t// If the response is not 2xx, still parse the response body as JSON\n\t\t\t// but throw the JSON as error.\n\t\t\tif ( ! response.ok ) {\n\t\t\t\treturn parseAndThrowError( response, parse );\n\t\t\t}\n\n\t\t\treturn parseResponseAndNormalizeError( response, parse );\n\t\t},\n\t\t( err ) => {\n\t\t\t// Re-throw AbortError for the users to handle it themselves.\n\t\t\tif ( err && err.name === 'AbortError' ) {\n\t\t\t\tthrow err;\n\t\t\t}\n\n\t\t\t// If the browser reports being offline, we'll just assume that\n\t\t\t// this is why the request failed.\n\t\t\tif ( ! globalThis.navigator.onLine ) {\n\t\t\t\tthrow {\n\t\t\t\t\tcode: 'offline_error',\n\t\t\t\t\tmessage: __(\n\t\t\t\t\t\t'Unable to connect. Please check your Internet connection.'\n\t\t\t\t\t),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Hard to diagnose further due to how Window.fetch reports errors.\n\t\t\tthrow {\n\t\t\t\tcode: 'fetch_error',\n\t\t\t\tmessage: __(\n\t\t\t\t\t'Could not get a valid response from the server.'\n\t\t\t\t),\n\t\t\t};\n\t\t}\n\t);\n};\n\nlet fetchHandler = defaultFetchHandler;\n\n/**\n * Defines a custom fetch handler for making the requests that will override\n * the default one using window.fetch\n *\n * @param newFetchHandler The new fetch handler\n */\nfunction setFetchHandler( newFetchHandler: FetchHandler ) {\n\tfetchHandler = newFetchHandler;\n}\n\nexport interface ApiFetch {\n\t< T, Parse extends boolean = true >(\n\t\toptions: APIFetchOptions< Parse >\n\t): Promise< Parse extends true ? T : Response >;\n\tnonceEndpoint?: string;\n\tnonceMiddleware?: ReturnType< typeof createNonceMiddleware >;\n\tuse: ( middleware: APIFetchMiddleware ) => void;\n\tsetFetchHandler: ( newFetchHandler: FetchHandler ) => void;\n\tcreateNonceMiddleware: typeof createNonceMiddleware;\n\tcreatePreloadingMiddleware: typeof createPreloadingMiddleware;\n\tcreateRootURLMiddleware: typeof createRootURLMiddleware;\n\tfetchAllMiddleware: typeof fetchAllMiddleware;\n\tmediaUploadMiddleware: typeof mediaUploadMiddleware;\n\tcreateThemePreviewMiddleware: typeof createThemePreviewMiddleware;\n}\n\n/**\n * Fetch\n *\n * @param options The options for the fetch.\n * @return A promise representing the request processed via the registered middlewares.\n */\nconst apiFetch: ApiFetch = ( options ) => {\n\t// creates a nested function chain that calls all middlewares and finally the `fetchHandler`,\n\t// converting `middlewares = [ m1, m2, m3 ]` into:\n\t// ```\n\t// opts1 => m1( opts1, opts2 => m2( opts2, opts3 => m3( opts3, fetchHandler ) ) );\n\t// ```\n\tconst enhancedHandler = middlewares.reduceRight< FetchHandler >(\n\t\t( next, middleware ) => {\n\t\t\treturn ( workingOptions ) => middleware( workingOptions, next );\n\t\t},\n\t\tfetchHandler\n\t);\n\n\treturn enhancedHandler( options ).catch( ( error ) => {\n\t\tif ( error.code !== 'rest_cookie_invalid_nonce' ) {\n\t\t\treturn Promise.reject( error );\n\t\t}\n\n\t\t// If the nonce is invalid, refresh it and try again.\n\t\treturn globalThis\n\t\t\t.fetch( apiFetch.nonceEndpoint! )\n\t\t\t.then( ( response ) => {\n\t\t\t\t// If the nonce refresh fails, it means we failed to recover from the original\n\t\t\t\t// `rest_cookie_invalid_nonce` error and that it's time to finally re-throw it.\n\t\t\t\tif ( ! response.ok ) {\n\t\t\t\t\treturn Promise.reject( error );\n\t\t\t\t}\n\n\t\t\t\treturn response.text();\n\t\t\t} )\n\t\t\t.then( ( text ) => {\n\t\t\t\tapiFetch.nonceMiddleware!.nonce = text;\n\t\t\t\treturn apiFetch( options );\n\t\t\t} );\n\t} );\n};\n\napiFetch.use = registerMiddleware;\napiFetch.setFetchHandler = setFetchHandler;\n\napiFetch.createNonceMiddleware = createNonceMiddleware;\napiFetch.createPreloadingMiddleware = createPreloadingMiddleware;\napiFetch.createRootURLMiddleware = createRootURLMiddleware;\napiFetch.fetchAllMiddleware = fetchAllMiddleware;\napiFetch.mediaUploadMiddleware = mediaUploadMiddleware;\napiFetch.createThemePreviewMiddleware = createThemePreviewMiddleware;\n\nexport default apiFetch;\nexport type * from './types';\n"],
5
- "mappings": ";AAGA,SAAS,UAAU;AAKnB,OAAO,2BAA2B;AAClC,OAAO,6BAA6B;AACpC,OAAO,gCAAgC;AACvC,OAAO,wBAAwB;AAC/B,OAAO,iCAAiC;AACxC,OAAO,sBAAsB;AAC7B,OAAO,0BAA0B;AACjC,OAAO,2BAA2B;AAClC,OAAO,kCAAkC;AACzC;AAAA,EACC;AAAA,EACA;AAAA,OACM;AAWP,IAAM,kBAAgD;AAAA;AAAA;AAAA;AAAA;AAAA,EAKrD,QAAQ;AACT;AAMA,IAAM,kBAAmC;AAAA,EACxC,aAAa;AACd;AAEA,IAAM,cAA2C;AAAA,EAChD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAOA,SAAS,mBAAoB,YAAiC;AAC7D,cAAY,QAAS,UAAW;AACjC;AAEA,IAAM,sBAAoC,CAAE,gBAAiB;AAC5D,QAAM,EAAE,KAAK,MAAM,MAAM,QAAQ,MAAM,GAAG,iBAAiB,IAAI;AAC/D,MAAI,EAAE,MAAM,QAAQ,IAAI;AAGxB,YAAU,EAAE,GAAG,iBAAiB,GAAG,QAAQ;AAG3C,MAAK,MAAO;AACX,WAAO,KAAK,UAAW,IAAK;AAC5B,YAAS,cAAe,IAAI;AAAA,EAC7B;AAEA,QAAM,kBAAkB,WAAW;AAAA;AAAA,IAElC,OAAO,QAAQ,OAAO,SAAS;AAAA,IAC/B;AAAA,MACC,GAAG;AAAA,MACH,GAAG;AAAA,MACH;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAEA,SAAO,gBAAgB;AAAA,IACtB,CAAE,aAAc;AAGf,UAAK,CAAE,SAAS,IAAK;AACpB,eAAO,mBAAoB,UAAU,KAAM;AAAA,MAC5C;AAEA,aAAO,+BAAgC,UAAU,KAAM;AAAA,IACxD;AAAA,IACA,CAAE,QAAS;AAEV,UAAK,OAAO,IAAI,SAAS,cAAe;AACvC,cAAM;AAAA,MACP;AAIA,UAAK,CAAE,WAAW,UAAU,QAAS;AACpC,cAAM;AAAA,UACL,MAAM;AAAA,UACN,SAAS;AAAA,YACR;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAGA,YAAM;AAAA,QACL,MAAM;AAAA,QACN,SAAS;AAAA,UACR;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACD;AAEA,IAAI,eAAe;AAQnB,SAAS,gBAAiB,iBAAgC;AACzD,iBAAe;AAChB;AAwBA,IAAM,WAAqB,CAAE,YAAa;AAMzC,QAAM,kBAAkB,YAAY;AAAA,IACnC,CAAE,MAAM,eAAgB;AACvB,aAAO,CAAE,mBAAoB,WAAY,gBAAgB,IAAK;AAAA,IAC/D;AAAA,IACA;AAAA,EACD;AAEA,SAAO,gBAAiB,OAAQ,EAAE,MAAO,CAAE,UAAW;AACrD,QAAK,MAAM,SAAS,6BAA8B;AACjD,aAAO,QAAQ,OAAQ,KAAM;AAAA,IAC9B;AAGA,WAAO,WACL,MAAO,SAAS,aAAe,EAC/B,KAAM,CAAE,aAAc;AAGtB,UAAK,CAAE,SAAS,IAAK;AACpB,eAAO,QAAQ,OAAQ,KAAM;AAAA,MAC9B;AAEA,aAAO,SAAS,KAAK;AAAA,IACtB,CAAE,EACD,KAAM,CAAE,SAAU;AAClB,eAAS,gBAAiB,QAAQ;AAClC,aAAO,SAAU,OAAQ;AAAA,IAC1B,CAAE;AAAA,EACJ,CAAE;AACH;AAEA,SAAS,MAAM;AACf,SAAS,kBAAkB;AAE3B,SAAS,wBAAwB;AACjC,SAAS,6BAA6B;AACtC,SAAS,0BAA0B;AACnC,SAAS,qBAAqB;AAC9B,SAAS,wBAAwB;AACjC,SAAS,+BAA+B;AAExC,IAAO,gBAAQ;",
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { __ } from '@wordpress/i18n';\n\n/**\n * Internal dependencies\n */\nimport { lock } from './lock-unlock';\nimport createNonceMiddleware from './middlewares/nonce';\nimport createRootURLMiddleware from './middlewares/root-url';\nimport createPreloadingMiddleware, {\n\tCLEAR as PRELOADING_CLEAR,\n\tENABLE_MULTI_USE as PRELOADING_ENABLE_MULTI_USE,\n} from './middlewares/preloading';\nimport fetchAllMiddleware from './middlewares/fetch-all-middleware';\nimport namespaceEndpointMiddleware from './middlewares/namespace-endpoint';\nimport httpV1Middleware from './middlewares/http-v1';\nimport userLocaleMiddleware from './middlewares/user-locale';\nimport mediaUploadMiddleware from './middlewares/media-upload';\nimport createThemePreviewMiddleware from './middlewares/theme-preview';\nimport {\n\tparseResponseAndNormalizeError,\n\tparseAndThrowError,\n} from './utils/response';\nimport type {\n\tAPIFetchMiddleware,\n\tAPIFetchOptions,\n\tFetchHandler,\n} from './types';\n\n/**\n * Default set of header values which should be sent with every request unless\n * explicitly provided through apiFetch options.\n */\nconst DEFAULT_HEADERS: APIFetchOptions[ 'headers' ] = {\n\t// The backend uses the Accept header as a condition for considering an\n\t// incoming request as a REST request.\n\t//\n\t// See: https://core.trac.wordpress.org/ticket/44534\n\tAccept: 'application/json, */*;q=0.1',\n};\n\n/**\n * Default set of fetch option values which should be sent with every request\n * unless explicitly provided through apiFetch options.\n */\nconst DEFAULT_OPTIONS: APIFetchOptions = {\n\tcredentials: 'include',\n};\n\nconst middlewares: Array< APIFetchMiddleware > = [\n\tuserLocaleMiddleware,\n\tnamespaceEndpointMiddleware,\n\thttpV1Middleware,\n\tfetchAllMiddleware,\n];\n\n/**\n * Register a middleware\n *\n * @param middleware\n */\nfunction registerMiddleware( middleware: APIFetchMiddleware ) {\n\tmiddlewares.unshift( middleware );\n}\n\nfunction enablePreloadMultiUse() {\n\tfor ( const middleware of middlewares ) {\n\t\t( middleware as any )[ PRELOADING_ENABLE_MULTI_USE ]?.();\n\t}\n}\n\nfunction clearPreloadedData() {\n\tfor ( const middleware of middlewares ) {\n\t\t( middleware as any )[ PRELOADING_CLEAR ]?.();\n\t}\n}\n\nconst defaultFetchHandler: FetchHandler = ( nextOptions ) => {\n\tconst { url, path, data, parse = true, ...remainingOptions } = nextOptions;\n\tlet { body, headers } = nextOptions;\n\n\t// Merge explicitly-provided headers with default values.\n\theaders = { ...DEFAULT_HEADERS, ...headers };\n\n\t// The `data` property is a shorthand for sending a JSON body.\n\tif ( data ) {\n\t\tbody = JSON.stringify( data );\n\t\theaders[ 'Content-Type' ] = 'application/json';\n\t}\n\n\tconst responsePromise = globalThis.fetch(\n\t\t// Fall back to explicitly passing `window.location` which is the behavior if `undefined` is passed.\n\t\turl || path || window.location.href,\n\t\t{\n\t\t\t...DEFAULT_OPTIONS,\n\t\t\t...remainingOptions,\n\t\t\tbody,\n\t\t\theaders,\n\t\t}\n\t);\n\n\treturn responsePromise.then(\n\t\t( response ) => {\n\t\t\t// If the response is not 2xx, still parse the response body as JSON\n\t\t\t// but throw the JSON as error.\n\t\t\tif ( ! response.ok ) {\n\t\t\t\treturn parseAndThrowError( response, parse );\n\t\t\t}\n\n\t\t\treturn parseResponseAndNormalizeError( response, parse );\n\t\t},\n\t\t( err ) => {\n\t\t\t// Re-throw AbortError for the users to handle it themselves.\n\t\t\tif ( err && err.name === 'AbortError' ) {\n\t\t\t\tthrow err;\n\t\t\t}\n\n\t\t\t// If the browser reports being offline, we'll just assume that\n\t\t\t// this is why the request failed.\n\t\t\tif ( ! globalThis.navigator.onLine ) {\n\t\t\t\tthrow {\n\t\t\t\t\tcode: 'offline_error',\n\t\t\t\t\tmessage: __(\n\t\t\t\t\t\t'Unable to connect. Please check your Internet connection.'\n\t\t\t\t\t),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Hard to diagnose further due to how Window.fetch reports errors.\n\t\t\tthrow {\n\t\t\t\tcode: 'fetch_error',\n\t\t\t\tmessage: __(\n\t\t\t\t\t'Could not get a valid response from the server.'\n\t\t\t\t),\n\t\t\t};\n\t\t}\n\t);\n};\n\nlet fetchHandler = defaultFetchHandler;\n\n/**\n * Defines a custom fetch handler for making the requests that will override\n * the default one using window.fetch\n *\n * @param newFetchHandler The new fetch handler\n */\nfunction setFetchHandler( newFetchHandler: FetchHandler ) {\n\tfetchHandler = newFetchHandler;\n}\n\nexport interface ApiFetch {\n\t< T, Parse extends boolean = true >(\n\t\toptions: APIFetchOptions< Parse >\n\t): Promise< Parse extends true ? T : Response >;\n\tnonceEndpoint?: string;\n\tnonceMiddleware?: ReturnType< typeof createNonceMiddleware >;\n\tuse: ( middleware: APIFetchMiddleware ) => void;\n\tsetFetchHandler: ( newFetchHandler: FetchHandler ) => void;\n\tcreateNonceMiddleware: typeof createNonceMiddleware;\n\tcreatePreloadingMiddleware: typeof createPreloadingMiddleware;\n\tcreateRootURLMiddleware: typeof createRootURLMiddleware;\n\tfetchAllMiddleware: typeof fetchAllMiddleware;\n\tmediaUploadMiddleware: typeof mediaUploadMiddleware;\n\tcreateThemePreviewMiddleware: typeof createThemePreviewMiddleware;\n\tprivateApis: object;\n}\n\n/**\n * Fetch\n *\n * @param options The options for the fetch.\n * @return A promise representing the request processed via the registered middlewares.\n */\nconst apiFetch: ApiFetch = ( options ) => {\n\t// creates a nested function chain that calls all middlewares and finally the `fetchHandler`,\n\t// converting `middlewares = [ m1, m2, m3 ]` into:\n\t// ```\n\t// opts1 => m1( opts1, opts2 => m2( opts2, opts3 => m3( opts3, fetchHandler ) ) );\n\t// ```\n\tconst enhancedHandler = middlewares.reduceRight< FetchHandler >(\n\t\t( next, middleware ) => {\n\t\t\treturn ( workingOptions ) => middleware( workingOptions, next );\n\t\t},\n\t\tfetchHandler\n\t);\n\n\treturn enhancedHandler( options ).catch( ( error ) => {\n\t\tif ( error.code !== 'rest_cookie_invalid_nonce' ) {\n\t\t\treturn Promise.reject( error );\n\t\t}\n\n\t\t// If the nonce is invalid, refresh it and try again.\n\t\treturn globalThis\n\t\t\t.fetch( apiFetch.nonceEndpoint! )\n\t\t\t.then( ( response ) => {\n\t\t\t\t// If the nonce refresh fails, it means we failed to recover from the original\n\t\t\t\t// `rest_cookie_invalid_nonce` error and that it's time to finally re-throw it.\n\t\t\t\tif ( ! response.ok ) {\n\t\t\t\t\treturn Promise.reject( error );\n\t\t\t\t}\n\n\t\t\t\treturn response.text();\n\t\t\t} )\n\t\t\t.then( ( text ) => {\n\t\t\t\tapiFetch.nonceMiddleware!.nonce = text;\n\t\t\t\treturn apiFetch( options );\n\t\t\t} );\n\t} );\n};\n\napiFetch.use = registerMiddleware;\napiFetch.setFetchHandler = setFetchHandler;\n\n// Attached to the function (rather than a named export) because\n// `wpScriptDefaultExport: true` flattens this module to its default\n// export \u2014 `wp.apiFetch` is the function itself, so anything that\n// needs to be reachable from a consumer's `wp.apiFetch.X` lookup has\n// to live on the function.\napiFetch.privateApis = {};\nlock( apiFetch.privateApis, {\n\tenablePreloadMultiUse,\n\tclearPreloadedData,\n} );\n\napiFetch.createNonceMiddleware = createNonceMiddleware;\napiFetch.createPreloadingMiddleware = createPreloadingMiddleware;\napiFetch.createRootURLMiddleware = createRootURLMiddleware;\napiFetch.fetchAllMiddleware = fetchAllMiddleware;\napiFetch.mediaUploadMiddleware = mediaUploadMiddleware;\napiFetch.createThemePreviewMiddleware = createThemePreviewMiddleware;\n\nexport default apiFetch;\nexport type * from './types';\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,11 @@
1
+ // packages/api-fetch/src/lock-unlock.ts
2
+ import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from "@wordpress/private-apis";
3
+ var { lock, unlock } = __dangerousOptInToUnstableAPIsOnlyForCoreModules(
4
+ "I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.",
5
+ "@wordpress/api-fetch"
6
+ );
7
+ export {
8
+ lock,
9
+ unlock
10
+ };
11
+ //# sourceMappingURL=lock-unlock.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/lock-unlock.ts"],
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/private-apis';\n\nexport const { lock, unlock } =\n\t__dangerousOptInToUnstableAPIsOnlyForCoreModules(\n\t\t'I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.',\n\t\t'@wordpress/api-fetch'\n\t);\n"],
5
+ "mappings": ";AAGA,SAAS,wDAAwD;AAE1D,IAAM,EAAE,MAAM,OAAO,IAC3B;AAAA,EACC;AAAA,EACA;AACD;",
6
+ "names": []
7
+ }
@@ -1,13 +1,18 @@
1
1
  // packages/api-fetch/src/middlewares/preloading.ts
2
2
  import { addQueryArgs, getQueryArgs, normalizePath } from "@wordpress/url";
3
+ var ENABLE_MULTI_USE = /* @__PURE__ */ Symbol("preloadingEnableMultiUse");
4
+ var CLEAR = /* @__PURE__ */ Symbol("preloadingClear");
3
5
  function createPreloadingMiddleware(preloadedData) {
4
- const cache = Object.fromEntries(
6
+ const { OPTIONS = {}, ...GET } = Object.fromEntries(
5
7
  Object.entries(preloadedData).map(([path, data]) => [
6
8
  normalizePath(path),
7
9
  data
8
10
  ])
9
11
  );
10
- return (options, next) => {
12
+ const unusedGet = new Set(Object.keys(GET));
13
+ const unusedOptions = new Set(Object.keys(OPTIONS));
14
+ let multiUse = false;
15
+ const middleware = (options, next) => {
11
16
  const { parse = true } = options;
12
17
  let rawPath = options.path;
13
18
  if (!rawPath && options.url) {
@@ -23,17 +28,49 @@ function createPreloadingMiddleware(preloadedData) {
23
28
  }
24
29
  const method = options.method || "GET";
25
30
  const path = normalizePath(rawPath);
26
- if ("GET" === method && cache[path]) {
27
- const cacheData = cache[path];
28
- delete cache[path];
29
- return prepareResponse(cacheData, !!parse);
30
- } else if ("OPTIONS" === method && cache[method] && cache[method][path]) {
31
- const cacheData = cache[method][path];
32
- delete cache[method][path];
33
- return prepareResponse(cacheData, !!parse);
31
+ if ("GET" === method && GET[path]) {
32
+ const data = GET[path];
33
+ if (!multiUse) {
34
+ delete GET[path];
35
+ }
36
+ unusedGet.delete(path);
37
+ return prepareResponse(data, !!parse);
38
+ } else if ("OPTIONS" === method && OPTIONS[path]) {
39
+ const data = OPTIONS[path];
40
+ if (!multiUse) {
41
+ delete OPTIONS[path];
42
+ }
43
+ unusedOptions.delete(path);
44
+ return prepareResponse(data, !!parse);
34
45
  }
35
46
  return next(options);
36
47
  };
48
+ middleware[ENABLE_MULTI_USE] = () => {
49
+ multiUse = true;
50
+ };
51
+ middleware[CLEAR] = () => {
52
+ const tags = [
53
+ ...Array.from(unusedGet, (p) => `GET ${p}`),
54
+ ...Array.from(unusedOptions, (p) => `OPTIONS ${p}`)
55
+ ];
56
+ if (tags.length) {
57
+ console.warn(
58
+ "[api-fetch][preload] Some preloads were never consumed:",
59
+ tags
60
+ );
61
+ } else {
62
+ console.log("[api-fetch][preload] All preloads consumed.");
63
+ }
64
+ unusedGet.clear();
65
+ unusedOptions.clear();
66
+ for (const key of Object.keys(GET)) {
67
+ delete GET[key];
68
+ }
69
+ for (const key of Object.keys(OPTIONS)) {
70
+ delete OPTIONS[key];
71
+ }
72
+ };
73
+ return middleware;
37
74
  }
38
75
  function prepareResponse(responseData, parse) {
39
76
  if (parse) {
@@ -69,6 +106,8 @@ function prepareResponse(responseData, parse) {
69
106
  }
70
107
  var preloading_default = createPreloadingMiddleware;
71
108
  export {
109
+ CLEAR,
110
+ ENABLE_MULTI_USE,
72
111
  preloading_default as default
73
112
  };
74
113
  //# sourceMappingURL=preloading.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/middlewares/preloading.ts"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { addQueryArgs, getQueryArgs, normalizePath } from '@wordpress/url';\n\n/**\n * Internal dependencies\n */\nimport type { APIFetchMiddleware } from '../types';\n\n/**\n * @param preloadedData\n * @return Preloading middleware.\n */\nfunction createPreloadingMiddleware(\n\tpreloadedData: Record< string, any >\n): APIFetchMiddleware {\n\tconst cache = Object.fromEntries(\n\t\tObject.entries( preloadedData ).map( ( [ path, data ] ) => [\n\t\t\tnormalizePath( path ),\n\t\t\tdata,\n\t\t] )\n\t);\n\n\treturn ( options, next ) => {\n\t\tconst { parse = true } = options;\n\t\tlet rawPath = options.path;\n\t\tif ( ! rawPath && options.url ) {\n\t\t\tconst { rest_route: pathFromQuery, ...queryArgs } = getQueryArgs(\n\t\t\t\toptions.url\n\t\t\t);\n\n\t\t\tif ( typeof pathFromQuery === 'string' ) {\n\t\t\t\trawPath = addQueryArgs( pathFromQuery, queryArgs );\n\t\t\t}\n\t\t}\n\n\t\tif ( typeof rawPath !== 'string' ) {\n\t\t\treturn next( options );\n\t\t}\n\n\t\tconst method = options.method || 'GET';\n\t\tconst path = normalizePath( rawPath );\n\n\t\tif ( 'GET' === method && cache[ path ] ) {\n\t\t\tconst cacheData = cache[ path ];\n\n\t\t\t// Unsetting the cache key ensures that the data is only used a single time.\n\t\t\tdelete cache[ path ];\n\n\t\t\treturn prepareResponse( cacheData, !! parse );\n\t\t} else if (\n\t\t\t'OPTIONS' === method &&\n\t\t\tcache[ method ] &&\n\t\t\tcache[ method ][ path ]\n\t\t) {\n\t\t\tconst cacheData = cache[ method ][ path ];\n\n\t\t\t// Unsetting the cache key ensures that the data is only used a single time.\n\t\t\tdelete cache[ method ][ path ];\n\n\t\t\treturn prepareResponse( cacheData, !! parse );\n\t\t}\n\n\t\treturn next( options );\n\t};\n}\n\n/**\n * This is a helper function that sends a success response.\n *\n * @param responseData\n * @param parse\n * @return Promise with the response.\n */\nfunction prepareResponse(\n\tresponseData: Record< string, any >,\n\tparse: boolean\n) {\n\tif ( parse ) {\n\t\treturn Promise.resolve( responseData.body );\n\t}\n\n\ttry {\n\t\treturn Promise.resolve(\n\t\t\tnew window.Response( JSON.stringify( responseData.body ), {\n\t\t\t\tstatus: 200,\n\t\t\t\tstatusText: 'OK',\n\t\t\t\theaders: responseData.headers,\n\t\t\t} )\n\t\t);\n\t} catch {\n\t\t// See: https://github.com/WordPress/gutenberg/issues/67358#issuecomment-2621163926.\n\t\tObject.entries(\n\t\t\tresponseData.headers as Record< string, string >\n\t\t).forEach( ( [ key, value ] ) => {\n\t\t\tif ( key.toLowerCase() === 'link' ) {\n\t\t\t\tresponseData.headers[ key ] = value.replace(\n\t\t\t\t\t/<([^>]+)>/,\n\t\t\t\t\t( _, url ) => `<${ encodeURI( url ) }>`\n\t\t\t\t);\n\t\t\t}\n\t\t} );\n\n\t\treturn Promise.resolve(\n\t\t\tparse\n\t\t\t\t? responseData.body\n\t\t\t\t: new window.Response( JSON.stringify( responseData.body ), {\n\t\t\t\t\t\tstatus: 200,\n\t\t\t\t\t\tstatusText: 'OK',\n\t\t\t\t\t\theaders: responseData.headers,\n\t\t\t\t } )\n\t\t);\n\t}\n}\n\nexport default createPreloadingMiddleware;\n"],
5
- "mappings": ";AAGA,SAAS,cAAc,cAAc,qBAAqB;AAW1D,SAAS,2BACR,eACqB;AACrB,QAAM,QAAQ,OAAO;AAAA,IACpB,OAAO,QAAS,aAAc,EAAE,IAAK,CAAE,CAAE,MAAM,IAAK,MAAO;AAAA,MAC1D,cAAe,IAAK;AAAA,MACpB;AAAA,IACD,CAAE;AAAA,EACH;AAEA,SAAO,CAAE,SAAS,SAAU;AAC3B,UAAM,EAAE,QAAQ,KAAK,IAAI;AACzB,QAAI,UAAU,QAAQ;AACtB,QAAK,CAAE,WAAW,QAAQ,KAAM;AAC/B,YAAM,EAAE,YAAY,eAAe,GAAG,UAAU,IAAI;AAAA,QACnD,QAAQ;AAAA,MACT;AAEA,UAAK,OAAO,kBAAkB,UAAW;AACxC,kBAAU,aAAc,eAAe,SAAU;AAAA,MAClD;AAAA,IACD;AAEA,QAAK,OAAO,YAAY,UAAW;AAClC,aAAO,KAAM,OAAQ;AAAA,IACtB;AAEA,UAAM,SAAS,QAAQ,UAAU;AACjC,UAAM,OAAO,cAAe,OAAQ;AAEpC,QAAK,UAAU,UAAU,MAAO,IAAK,GAAI;AACxC,YAAM,YAAY,MAAO,IAAK;AAG9B,aAAO,MAAO,IAAK;AAEnB,aAAO,gBAAiB,WAAW,CAAC,CAAE,KAAM;AAAA,IAC7C,WACC,cAAc,UACd,MAAO,MAAO,KACd,MAAO,MAAO,EAAG,IAAK,GACrB;AACD,YAAM,YAAY,MAAO,MAAO,EAAG,IAAK;AAGxC,aAAO,MAAO,MAAO,EAAG,IAAK;AAE7B,aAAO,gBAAiB,WAAW,CAAC,CAAE,KAAM;AAAA,IAC7C;AAEA,WAAO,KAAM,OAAQ;AAAA,EACtB;AACD;AASA,SAAS,gBACR,cACA,OACC;AACD,MAAK,OAAQ;AACZ,WAAO,QAAQ,QAAS,aAAa,IAAK;AAAA,EAC3C;AAEA,MAAI;AACH,WAAO,QAAQ;AAAA,MACd,IAAI,OAAO,SAAU,KAAK,UAAW,aAAa,IAAK,GAAG;AAAA,QACzD,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,SAAS,aAAa;AAAA,MACvB,CAAE;AAAA,IACH;AAAA,EACD,QAAQ;AAEP,WAAO;AAAA,MACN,aAAa;AAAA,IACd,EAAE,QAAS,CAAE,CAAE,KAAK,KAAM,MAAO;AAChC,UAAK,IAAI,YAAY,MAAM,QAAS;AACnC,qBAAa,QAAS,GAAI,IAAI,MAAM;AAAA,UACnC;AAAA,UACA,CAAE,GAAG,QAAS,IAAK,UAAW,GAAI,CAAE;AAAA,QACrC;AAAA,MACD;AAAA,IACD,CAAE;AAEF,WAAO,QAAQ;AAAA,MACd,QACG,aAAa,OACb,IAAI,OAAO,SAAU,KAAK,UAAW,aAAa,IAAK,GAAG;AAAA,QAC1D,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,SAAS,aAAa;AAAA,MACtB,CAAE;AAAA,IACN;AAAA,EACD;AACD;AAEA,IAAO,qBAAQ;",
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { addQueryArgs, getQueryArgs, normalizePath } from '@wordpress/url';\n\n/**\n * Internal dependencies\n */\nimport type { APIFetchMiddleware } from '../types';\n\nexport const ENABLE_MULTI_USE = Symbol( 'preloadingEnableMultiUse' );\nexport const CLEAR = Symbol( 'preloadingClear' );\n\n/**\n * @param preloadedData\n * @return Preloading middleware.\n */\nfunction createPreloadingMiddleware(\n\tpreloadedData: Record< string, any >\n): APIFetchMiddleware {\n\tconst { OPTIONS = {}, ...GET } = Object.fromEntries(\n\t\tObject.entries( preloadedData ).map( ( [ path, data ] ) => [\n\t\t\tnormalizePath( path ),\n\t\t\tdata,\n\t\t] )\n\t) as Record< string, any > & { OPTIONS?: Record< string, any > };\n\n\t// Preload entries that haven't been served yet.\n\tconst unusedGet = new Set< string >( Object.keys( GET ) );\n\tconst unusedOptions = new Set< string >( Object.keys( OPTIONS ) );\n\n\tlet multiUse = false;\n\n\tconst middleware: APIFetchMiddleware = ( options, next ) => {\n\t\tconst { parse = true } = options;\n\t\tlet rawPath = options.path;\n\t\tif ( ! rawPath && options.url ) {\n\t\t\tconst { rest_route: pathFromQuery, ...queryArgs } = getQueryArgs(\n\t\t\t\toptions.url\n\t\t\t);\n\n\t\t\tif ( typeof pathFromQuery === 'string' ) {\n\t\t\t\trawPath = addQueryArgs( pathFromQuery, queryArgs );\n\t\t\t}\n\t\t}\n\n\t\tif ( typeof rawPath !== 'string' ) {\n\t\t\treturn next( options );\n\t\t}\n\n\t\tconst method = options.method || 'GET';\n\t\tconst path = normalizePath( rawPath );\n\n\t\tif ( 'GET' === method && GET[ path ] ) {\n\t\t\tconst data = GET[ path ];\n\t\t\tif ( ! multiUse ) {\n\t\t\t\tdelete GET[ path ];\n\t\t\t}\n\t\t\tunusedGet.delete( path );\n\t\t\treturn prepareResponse( data, !! parse );\n\t\t} else if ( 'OPTIONS' === method && OPTIONS[ path ] ) {\n\t\t\tconst data = OPTIONS[ path ];\n\t\t\tif ( ! multiUse ) {\n\t\t\t\tdelete OPTIONS[ path ];\n\t\t\t}\n\t\t\tunusedOptions.delete( path );\n\t\t\treturn prepareResponse( data, !! parse );\n\t\t}\n\n\t\treturn next( options );\n\t};\n\n\t( middleware as any )[ ENABLE_MULTI_USE ] = () => {\n\t\tmultiUse = true;\n\t};\n\n\t( middleware as any )[ CLEAR ] = (): void => {\n\t\tconst tags = [\n\t\t\t...Array.from( unusedGet, ( p ) => `GET ${ p }` ),\n\t\t\t...Array.from( unusedOptions, ( p ) => `OPTIONS ${ p }` ),\n\t\t];\n\t\tif ( tags.length ) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(\n\t\t\t\t'[api-fetch][preload] Some preloads were never consumed:',\n\t\t\t\ttags\n\t\t\t);\n\t\t} else {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.log( '[api-fetch][preload] All preloads consumed.' );\n\t\t}\n\t\tunusedGet.clear();\n\t\tunusedOptions.clear();\n\t\tfor ( const key of Object.keys( GET ) ) {\n\t\t\tdelete GET[ key ];\n\t\t}\n\t\tfor ( const key of Object.keys( OPTIONS ) ) {\n\t\t\tdelete OPTIONS[ key ];\n\t\t}\n\t};\n\n\treturn middleware;\n}\n\n/**\n * This is a helper function that sends a success response.\n *\n * @param responseData\n * @param parse\n * @return Promise with the response.\n */\nfunction prepareResponse(\n\tresponseData: Record< string, any >,\n\tparse: boolean\n) {\n\tif ( parse ) {\n\t\treturn Promise.resolve( responseData.body );\n\t}\n\n\ttry {\n\t\treturn Promise.resolve(\n\t\t\tnew window.Response( JSON.stringify( responseData.body ), {\n\t\t\t\tstatus: 200,\n\t\t\t\tstatusText: 'OK',\n\t\t\t\theaders: responseData.headers,\n\t\t\t} )\n\t\t);\n\t} catch {\n\t\t// See: https://github.com/WordPress/gutenberg/issues/67358#issuecomment-2621163926.\n\t\tObject.entries(\n\t\t\tresponseData.headers as Record< string, string >\n\t\t).forEach( ( [ key, value ] ) => {\n\t\t\tif ( key.toLowerCase() === 'link' ) {\n\t\t\t\tresponseData.headers[ key ] = value.replace(\n\t\t\t\t\t/<([^>]+)>/,\n\t\t\t\t\t( _, url ) => `<${ encodeURI( url ) }>`\n\t\t\t\t);\n\t\t\t}\n\t\t} );\n\n\t\treturn Promise.resolve(\n\t\t\tparse\n\t\t\t\t? responseData.body\n\t\t\t\t: new window.Response( JSON.stringify( responseData.body ), {\n\t\t\t\t\t\tstatus: 200,\n\t\t\t\t\t\tstatusText: 'OK',\n\t\t\t\t\t\theaders: responseData.headers,\n\t\t\t\t } )\n\t\t);\n\t}\n}\n\nexport default createPreloadingMiddleware;\n"],
5
+ "mappings": ";AAGA,SAAS,cAAc,cAAc,qBAAqB;AAOnD,IAAM,mBAAmB,uBAAQ,0BAA2B;AAC5D,IAAM,QAAQ,uBAAQ,iBAAkB;AAM/C,SAAS,2BACR,eACqB;AACrB,QAAM,EAAE,UAAU,CAAC,GAAG,GAAG,IAAI,IAAI,OAAO;AAAA,IACvC,OAAO,QAAS,aAAc,EAAE,IAAK,CAAE,CAAE,MAAM,IAAK,MAAO;AAAA,MAC1D,cAAe,IAAK;AAAA,MACpB;AAAA,IACD,CAAE;AAAA,EACH;AAGA,QAAM,YAAY,IAAI,IAAe,OAAO,KAAM,GAAI,CAAE;AACxD,QAAM,gBAAgB,IAAI,IAAe,OAAO,KAAM,OAAQ,CAAE;AAEhE,MAAI,WAAW;AAEf,QAAM,aAAiC,CAAE,SAAS,SAAU;AAC3D,UAAM,EAAE,QAAQ,KAAK,IAAI;AACzB,QAAI,UAAU,QAAQ;AACtB,QAAK,CAAE,WAAW,QAAQ,KAAM;AAC/B,YAAM,EAAE,YAAY,eAAe,GAAG,UAAU,IAAI;AAAA,QACnD,QAAQ;AAAA,MACT;AAEA,UAAK,OAAO,kBAAkB,UAAW;AACxC,kBAAU,aAAc,eAAe,SAAU;AAAA,MAClD;AAAA,IACD;AAEA,QAAK,OAAO,YAAY,UAAW;AAClC,aAAO,KAAM,OAAQ;AAAA,IACtB;AAEA,UAAM,SAAS,QAAQ,UAAU;AACjC,UAAM,OAAO,cAAe,OAAQ;AAEpC,QAAK,UAAU,UAAU,IAAK,IAAK,GAAI;AACtC,YAAM,OAAO,IAAK,IAAK;AACvB,UAAK,CAAE,UAAW;AACjB,eAAO,IAAK,IAAK;AAAA,MAClB;AACA,gBAAU,OAAQ,IAAK;AACvB,aAAO,gBAAiB,MAAM,CAAC,CAAE,KAAM;AAAA,IACxC,WAAY,cAAc,UAAU,QAAS,IAAK,GAAI;AACrD,YAAM,OAAO,QAAS,IAAK;AAC3B,UAAK,CAAE,UAAW;AACjB,eAAO,QAAS,IAAK;AAAA,MACtB;AACA,oBAAc,OAAQ,IAAK;AAC3B,aAAO,gBAAiB,MAAM,CAAC,CAAE,KAAM;AAAA,IACxC;AAEA,WAAO,KAAM,OAAQ;AAAA,EACtB;AAEA,EAAE,WAAqB,gBAAiB,IAAI,MAAM;AACjD,eAAW;AAAA,EACZ;AAEA,EAAE,WAAqB,KAAM,IAAI,MAAY;AAC5C,UAAM,OAAO;AAAA,MACZ,GAAG,MAAM,KAAM,WAAW,CAAE,MAAO,OAAQ,CAAE,EAAG;AAAA,MAChD,GAAG,MAAM,KAAM,eAAe,CAAE,MAAO,WAAY,CAAE,EAAG;AAAA,IACzD;AACA,QAAK,KAAK,QAAS;AAElB,cAAQ;AAAA,QACP;AAAA,QACA;AAAA,MACD;AAAA,IACD,OAAO;AAEN,cAAQ,IAAK,6CAA8C;AAAA,IAC5D;AACA,cAAU,MAAM;AAChB,kBAAc,MAAM;AACpB,eAAY,OAAO,OAAO,KAAM,GAAI,GAAI;AACvC,aAAO,IAAK,GAAI;AAAA,IACjB;AACA,eAAY,OAAO,OAAO,KAAM,OAAQ,GAAI;AAC3C,aAAO,QAAS,GAAI;AAAA,IACrB;AAAA,EACD;AAEA,SAAO;AACR;AASA,SAAS,gBACR,cACA,OACC;AACD,MAAK,OAAQ;AACZ,WAAO,QAAQ,QAAS,aAAa,IAAK;AAAA,EAC3C;AAEA,MAAI;AACH,WAAO,QAAQ;AAAA,MACd,IAAI,OAAO,SAAU,KAAK,UAAW,aAAa,IAAK,GAAG;AAAA,QACzD,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,SAAS,aAAa;AAAA,MACvB,CAAE;AAAA,IACH;AAAA,EACD,QAAQ;AAEP,WAAO;AAAA,MACN,aAAa;AAAA,IACd,EAAE,QAAS,CAAE,CAAE,KAAK,KAAM,MAAO;AAChC,UAAK,IAAI,YAAY,MAAM,QAAS;AACnC,qBAAa,QAAS,GAAI,IAAI,MAAM;AAAA,UACnC;AAAA,UACA,CAAE,GAAG,QAAS,IAAK,UAAW,GAAI,CAAE;AAAA,QACrC;AAAA,MACD;AAAA,IACD,CAAE;AAEF,WAAO,QAAQ;AAAA,MACd,QACG,aAAa,OACb,IAAI,OAAO,SAAU,KAAK,UAAW,aAAa,IAAK,GAAG;AAAA,QAC1D,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,SAAS,aAAa;AAAA,MACtB,CAAE;AAAA,IACN;AAAA,EACD;AACD;AAEA,IAAO,qBAAQ;",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,3 @@
1
- /**
2
- * Internal dependencies
3
- */
4
1
  import createNonceMiddleware from './middlewares/nonce';
5
2
  import createRootURLMiddleware from './middlewares/root-url';
6
3
  import createPreloadingMiddleware from './middlewares/preloading';
@@ -20,6 +17,7 @@ export interface ApiFetch {
20
17
  fetchAllMiddleware: typeof fetchAllMiddleware;
21
18
  mediaUploadMiddleware: typeof mediaUploadMiddleware;
22
19
  createThemePreviewMiddleware: typeof createThemePreviewMiddleware;
20
+ privateApis: object;
23
21
  }
24
22
  /**
25
23
  * Fetch
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,OAAO,qBAAqB,MAAM,qBAAqB,CAAC;AACxD,OAAO,uBAAuB,MAAM,wBAAwB,CAAC;AAC7D,OAAO,0BAA0B,MAAM,0BAA0B,CAAC;AAClE,OAAO,kBAAkB,MAAM,oCAAoC,CAAC;AAIpE,OAAO,qBAAqB,MAAM,4BAA4B,CAAC;AAC/D,OAAO,4BAA4B,MAAM,6BAA6B,CAAC;AAKvE,OAAO,KAAK,EACX,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,MAAM,SAAS,CAAC;AAgHjB,MAAM,WAAW,QAAQ;IACxB,CAAE,CAAC,EAAE,KAAK,SAAS,OAAO,GAAG,IAAI,EAChC,OAAO,EAAE,eAAe,CAAE,KAAK,CAAE,GAC/B,OAAO,CAAE,KAAK,SAAS,IAAI,GAAG,CAAC,GAAG,QAAQ,CAAE,CAAC;IAChD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,UAAU,CAAE,OAAO,qBAAqB,CAAE,CAAC;IAC7D,GAAG,EAAE,CAAE,UAAU,EAAE,kBAAkB,KAAM,IAAI,CAAC;IAChD,eAAe,EAAE,CAAE,eAAe,EAAE,YAAY,KAAM,IAAI,CAAC;IAC3D,qBAAqB,EAAE,OAAO,qBAAqB,CAAC;IACpD,0BAA0B,EAAE,OAAO,0BAA0B,CAAC;IAC9D,uBAAuB,EAAE,OAAO,uBAAuB,CAAC;IACxD,kBAAkB,EAAE,OAAO,kBAAkB,CAAC;IAC9C,qBAAqB,EAAE,OAAO,qBAAqB,CAAC;IACpD,4BAA4B,EAAE,OAAO,4BAA4B,CAAC;CAClE;AAED;;;;;GAKG;AACH,QAAA,MAAM,QAAQ,EAAE,QAmCf,CAAC;eAYa,QAAQ;AACvB,mBAAmB,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,OAAO,qBAAqB,MAAM,qBAAqB,CAAC;AACxD,OAAO,uBAAuB,MAAM,wBAAwB,CAAC;AAC7D,OAAO,0BAGN,MAAM,0BAA0B,CAAC;AAClC,OAAO,kBAAkB,MAAM,oCAAoC,CAAC;AAIpE,OAAO,qBAAqB,MAAM,4BAA4B,CAAC;AAC/D,OAAO,4BAA4B,MAAM,6BAA6B,CAAC;AAKvE,OAAO,KAAK,EACX,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,MAAM,SAAS,CAAC;AA4HjB,MAAM,WAAW,QAAQ;IACxB,CAAE,CAAC,EAAE,KAAK,SAAS,OAAO,GAAG,IAAI,EAChC,OAAO,EAAE,eAAe,CAAE,KAAK,CAAE,GAC/B,OAAO,CAAE,KAAK,SAAS,IAAI,GAAG,CAAC,GAAG,QAAQ,CAAE,CAAC;IAChD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,UAAU,CAAE,OAAO,qBAAqB,CAAE,CAAC;IAC7D,GAAG,EAAE,CAAE,UAAU,EAAE,kBAAkB,KAAM,IAAI,CAAC;IAChD,eAAe,EAAE,CAAE,eAAe,EAAE,YAAY,KAAM,IAAI,CAAC;IAC3D,qBAAqB,EAAE,OAAO,qBAAqB,CAAC;IACpD,0BAA0B,EAAE,OAAO,0BAA0B,CAAC;IAC9D,uBAAuB,EAAE,OAAO,uBAAuB,CAAC;IACxD,kBAAkB,EAAE,OAAO,kBAAkB,CAAC;IAC9C,qBAAqB,EAAE,OAAO,qBAAqB,CAAC;IACpD,4BAA4B,EAAE,OAAO,4BAA4B,CAAC;IAClE,WAAW,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,QAAA,MAAM,QAAQ,EAAE,QAmCf,CAAC;eAuBa,QAAQ;AACvB,mBAAmB,SAAS,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const lock: (object: unknown, privateData: unknown) => void, unlock: <T = any>(object: unknown) => T;
2
+ //# sourceMappingURL=lock-unlock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock-unlock.d.ts","sourceRoot":"","sources":["../src/lock-unlock.ts"],"names":[],"mappings":"AAKA,eAAO,MAAQ,IAAI,mDAAE,MAAM,iCAIzB,CAAC"}
@@ -2,6 +2,8 @@
2
2
  * Internal dependencies
3
3
  */
4
4
  import type { APIFetchMiddleware } from '../types';
5
+ export declare const ENABLE_MULTI_USE: unique symbol;
6
+ export declare const CLEAR: unique symbol;
5
7
  /**
6
8
  * @param preloadedData
7
9
  * @return Preloading middleware.
@@ -1 +1 @@
1
- {"version":3,"file":"preloading.d.ts","sourceRoot":"","sources":["../../src/middlewares/preloading.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAEnD;;;GAGG;AACH,iBAAS,0BAA0B,CAClC,aAAa,EAAE,MAAM,CAAE,MAAM,EAAE,GAAG,CAAE,GAClC,kBAAkB,CAkDpB;eAkDc,0BAA0B"}
1
+ {"version":3,"file":"preloading.d.ts","sourceRoot":"","sources":["../../src/middlewares/preloading.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAEnD,eAAO,MAAM,gBAAgB,eAAuC,CAAC;AACrE,eAAO,MAAM,KAAK,eAA8B,CAAC;AAEjD;;;GAGG;AACH,iBAAS,0BAA0B,CAClC,aAAa,EAAE,MAAM,CAAE,MAAM,EAAE,GAAG,CAAE,GAClC,kBAAkB,CAmFpB;eAkDc,0BAA0B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/api-fetch",
3
- "version": "7.46.0",
3
+ "version": "7.47.0",
4
4
  "description": "Utility to make WordPress REST API requests.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -45,11 +45,12 @@
45
45
  "wpScriptDefaultExport": true,
46
46
  "types": "build-types",
47
47
  "dependencies": {
48
- "@wordpress/i18n": "^6.19.0",
49
- "@wordpress/url": "^4.46.0"
48
+ "@wordpress/i18n": "^6.20.0",
49
+ "@wordpress/private-apis": "^1.47.0",
50
+ "@wordpress/url": "^4.47.0"
50
51
  },
51
52
  "publishConfig": {
52
53
  "access": "public"
53
54
  },
54
- "gitHead": "51264e33b95fadff9a06b68141e674ce9cde9675"
55
+ "gitHead": "d653c5fd6161571a0c2ebde28553d6e25624eacc"
55
56
  }
package/src/index.ts CHANGED
@@ -6,9 +6,13 @@ import { __ } from '@wordpress/i18n';
6
6
  /**
7
7
  * Internal dependencies
8
8
  */
9
+ import { lock } from './lock-unlock';
9
10
  import createNonceMiddleware from './middlewares/nonce';
10
11
  import createRootURLMiddleware from './middlewares/root-url';
11
- import createPreloadingMiddleware from './middlewares/preloading';
12
+ import createPreloadingMiddleware, {
13
+ CLEAR as PRELOADING_CLEAR,
14
+ ENABLE_MULTI_USE as PRELOADING_ENABLE_MULTI_USE,
15
+ } from './middlewares/preloading';
12
16
  import fetchAllMiddleware from './middlewares/fetch-all-middleware';
13
17
  import namespaceEndpointMiddleware from './middlewares/namespace-endpoint';
14
18
  import httpV1Middleware from './middlewares/http-v1';
@@ -61,6 +65,18 @@ function registerMiddleware( middleware: APIFetchMiddleware ) {
61
65
  middlewares.unshift( middleware );
62
66
  }
63
67
 
68
+ function enablePreloadMultiUse() {
69
+ for ( const middleware of middlewares ) {
70
+ ( middleware as any )[ PRELOADING_ENABLE_MULTI_USE ]?.();
71
+ }
72
+ }
73
+
74
+ function clearPreloadedData() {
75
+ for ( const middleware of middlewares ) {
76
+ ( middleware as any )[ PRELOADING_CLEAR ]?.();
77
+ }
78
+ }
79
+
64
80
  const defaultFetchHandler: FetchHandler = ( nextOptions ) => {
65
81
  const { url, path, data, parse = true, ...remainingOptions } = nextOptions;
66
82
  let { body, headers } = nextOptions;
@@ -149,6 +165,7 @@ export interface ApiFetch {
149
165
  fetchAllMiddleware: typeof fetchAllMiddleware;
150
166
  mediaUploadMiddleware: typeof mediaUploadMiddleware;
151
167
  createThemePreviewMiddleware: typeof createThemePreviewMiddleware;
168
+ privateApis: object;
152
169
  }
153
170
 
154
171
  /**
@@ -197,6 +214,17 @@ const apiFetch: ApiFetch = ( options ) => {
197
214
  apiFetch.use = registerMiddleware;
198
215
  apiFetch.setFetchHandler = setFetchHandler;
199
216
 
217
+ // Attached to the function (rather than a named export) because
218
+ // `wpScriptDefaultExport: true` flattens this module to its default
219
+ // export — `wp.apiFetch` is the function itself, so anything that
220
+ // needs to be reachable from a consumer's `wp.apiFetch.X` lookup has
221
+ // to live on the function.
222
+ apiFetch.privateApis = {};
223
+ lock( apiFetch.privateApis, {
224
+ enablePreloadMultiUse,
225
+ clearPreloadedData,
226
+ } );
227
+
200
228
  apiFetch.createNonceMiddleware = createNonceMiddleware;
201
229
  apiFetch.createPreloadingMiddleware = createPreloadingMiddleware;
202
230
  apiFetch.createRootURLMiddleware = createRootURLMiddleware;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/private-apis';
5
+
6
+ export const { lock, unlock } =
7
+ __dangerousOptInToUnstableAPIsOnlyForCoreModules(
8
+ 'I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.',
9
+ '@wordpress/api-fetch'
10
+ );
@@ -8,6 +8,9 @@ import { addQueryArgs, getQueryArgs, normalizePath } from '@wordpress/url';
8
8
  */
9
9
  import type { APIFetchMiddleware } from '../types';
10
10
 
11
+ export const ENABLE_MULTI_USE = Symbol( 'preloadingEnableMultiUse' );
12
+ export const CLEAR = Symbol( 'preloadingClear' );
13
+
11
14
  /**
12
15
  * @param preloadedData
13
16
  * @return Preloading middleware.
@@ -15,14 +18,20 @@ import type { APIFetchMiddleware } from '../types';
15
18
  function createPreloadingMiddleware(
16
19
  preloadedData: Record< string, any >
17
20
  ): APIFetchMiddleware {
18
- const cache = Object.fromEntries(
21
+ const { OPTIONS = {}, ...GET } = Object.fromEntries(
19
22
  Object.entries( preloadedData ).map( ( [ path, data ] ) => [
20
23
  normalizePath( path ),
21
24
  data,
22
25
  ] )
23
- );
26
+ ) as Record< string, any > & { OPTIONS?: Record< string, any > };
27
+
28
+ // Preload entries that haven't been served yet.
29
+ const unusedGet = new Set< string >( Object.keys( GET ) );
30
+ const unusedOptions = new Set< string >( Object.keys( OPTIONS ) );
24
31
 
25
- return ( options, next ) => {
32
+ let multiUse = false;
33
+
34
+ const middleware: APIFetchMiddleware = ( options, next ) => {
26
35
  const { parse = true } = options;
27
36
  let rawPath = options.path;
28
37
  if ( ! rawPath && options.url ) {
@@ -42,28 +51,55 @@ function createPreloadingMiddleware(
42
51
  const method = options.method || 'GET';
43
52
  const path = normalizePath( rawPath );
44
53
 
45
- if ( 'GET' === method && cache[ path ] ) {
46
- const cacheData = cache[ path ];
47
-
48
- // Unsetting the cache key ensures that the data is only used a single time.
49
- delete cache[ path ];
54
+ if ( 'GET' === method && GET[ path ] ) {
55
+ const data = GET[ path ];
56
+ if ( ! multiUse ) {
57
+ delete GET[ path ];
58
+ }
59
+ unusedGet.delete( path );
60
+ return prepareResponse( data, !! parse );
61
+ } else if ( 'OPTIONS' === method && OPTIONS[ path ] ) {
62
+ const data = OPTIONS[ path ];
63
+ if ( ! multiUse ) {
64
+ delete OPTIONS[ path ];
65
+ }
66
+ unusedOptions.delete( path );
67
+ return prepareResponse( data, !! parse );
68
+ }
50
69
 
51
- return prepareResponse( cacheData, !! parse );
52
- } else if (
53
- 'OPTIONS' === method &&
54
- cache[ method ] &&
55
- cache[ method ][ path ]
56
- ) {
57
- const cacheData = cache[ method ][ path ];
70
+ return next( options );
71
+ };
58
72
 
59
- // Unsetting the cache key ensures that the data is only used a single time.
60
- delete cache[ method ][ path ];
73
+ ( middleware as any )[ ENABLE_MULTI_USE ] = () => {
74
+ multiUse = true;
75
+ };
61
76
 
62
- return prepareResponse( cacheData, !! parse );
77
+ ( middleware as any )[ CLEAR ] = (): void => {
78
+ const tags = [
79
+ ...Array.from( unusedGet, ( p ) => `GET ${ p }` ),
80
+ ...Array.from( unusedOptions, ( p ) => `OPTIONS ${ p }` ),
81
+ ];
82
+ if ( tags.length ) {
83
+ // eslint-disable-next-line no-console
84
+ console.warn(
85
+ '[api-fetch][preload] Some preloads were never consumed:',
86
+ tags
87
+ );
88
+ } else {
89
+ // eslint-disable-next-line no-console
90
+ console.log( '[api-fetch][preload] All preloads consumed.' );
91
+ }
92
+ unusedGet.clear();
93
+ unusedOptions.clear();
94
+ for ( const key of Object.keys( GET ) ) {
95
+ delete GET[ key ];
96
+ }
97
+ for ( const key of Object.keys( OPTIONS ) ) {
98
+ delete OPTIONS[ key ];
63
99
  }
64
-
65
- return next( options );
66
100
  };
101
+
102
+ return middleware;
67
103
  }
68
104
 
69
105
  /**
@@ -2,7 +2,10 @@
2
2
  * Internal dependencies
3
3
  */
4
4
  import type { FetchHandler } from '../../types';
5
- import createPreloadingMiddleware from '../preloading';
5
+ import createPreloadingMiddleware, {
6
+ CLEAR,
7
+ ENABLE_MULTI_USE,
8
+ } from '../preloading';
6
9
 
7
10
  describe( 'Preloading Middleware', () => {
8
11
  describe( 'given preloaded data', () => {
@@ -57,6 +60,40 @@ describe( 'Preloading Middleware', () => {
57
60
  preloadingMiddleware( requestOptions, nextSpy );
58
61
  expect( nextSpy ).toHaveBeenCalled();
59
62
  } );
63
+
64
+ it( 'keeps returning the preloaded data when multi-use is enabled', async () => {
65
+ const body = {
66
+ status: 'this is the preloaded response',
67
+ };
68
+ const preloadedData = {
69
+ 'wp/v2/posts': { body },
70
+ };
71
+ const preloadingMiddleware =
72
+ createPreloadingMiddleware( preloadedData );
73
+ ( preloadingMiddleware as any )[ ENABLE_MULTI_USE ]();
74
+
75
+ const requestOptions = {
76
+ method: 'GET',
77
+ path: 'wp/v2/posts',
78
+ };
79
+ const nextSpy = jest.fn();
80
+
81
+ await expect(
82
+ preloadingMiddleware( requestOptions, nextSpy )
83
+ ).resolves.toEqual( body );
84
+ await expect(
85
+ preloadingMiddleware( requestOptions, nextSpy )
86
+ ).resolves.toEqual( body );
87
+ expect( nextSpy ).not.toHaveBeenCalled();
88
+
89
+ // `CLEAR` is the explicit boundary at which
90
+ // subsequent requests should fall through. It also
91
+ // logs whether anything went unconsumed.
92
+ ( preloadingMiddleware as any )[ CLEAR ]();
93
+ expect( console ).toHaveLogged();
94
+ preloadingMiddleware( requestOptions, nextSpy );
95
+ expect( nextSpy ).toHaveBeenCalled();
96
+ } );
60
97
  } );
61
98
 
62
99
  describe( 'and the OPTIONS request has a parse flag', () => {