@remix-run/router 1.2.1 → 1.3.0-pre.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
@@ -1,5 +1,17 @@
1
1
  # `@remix-run/router`
2
2
 
3
+ ## 1.3.0-pre.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Expose deferred information from createStaticHandler ([#9760](https://github.com/remix-run/react-router/pull/9760))
8
+
9
+ ### Patch Changes
10
+
11
+ - Improved absolute redirect url detection in actions/loaders ([#9829](https://github.com/remix-run/react-router/pull/9829))
12
+ - Fix URL creation with memory histories ([#9814](https://github.com/remix-run/react-router/pull/9814))
13
+ - Fix `generatePath` when optional params are present ([#9764](https://github.com/remix-run/react-router/pull/9764))
14
+
3
15
  ## 1.2.1
4
16
 
5
17
  ### Patch Changes
package/dist/history.d.ts CHANGED
@@ -106,6 +106,12 @@ export interface History {
106
106
  * @param to - The destination URL
107
107
  */
108
108
  createHref(to: To): string;
109
+ /**
110
+ * Returns a URL for the given `to` value
111
+ *
112
+ * @param to - The destination URL
113
+ */
114
+ createURL(to: To): URL;
109
115
  /**
110
116
  * Encode a location the same way window.history would do (no-op for memory
111
117
  * history) so we ensure our PUSH/REPLACE navigations for data routers
@@ -231,7 +237,6 @@ export declare function createPath({ pathname, search, hash, }: Partial<Path>):
231
237
  * Parses a string URL path into its separate pathname, search, and hash components.
232
238
  */
233
239
  export declare function parsePath(path: string): Partial<Path>;
234
- export declare function createClientSideURL(location: Location | string): URL;
235
240
  export interface UrlHistory extends History {
236
241
  }
237
242
  export declare type UrlHistoryOptions = {
package/dist/index.d.ts CHANGED
@@ -1,8 +1,7 @@
1
- import { convertRoutesToDataRoutes, getPathContributingMatches } from "./utils";
2
1
  export type { ActionFunction, ActionFunctionArgs, AgnosticDataIndexRouteObject, AgnosticDataNonIndexRouteObject, AgnosticDataRouteMatch, AgnosticDataRouteObject, AgnosticIndexRouteObject, AgnosticNonIndexRouteObject, AgnosticRouteMatch, AgnosticRouteObject, TrackedPromise, FormEncType, FormMethod, JsonFunction, LoaderFunction, LoaderFunctionArgs, ParamParseKey, Params, PathMatch, PathPattern, RedirectFunction, ShouldRevalidateFunction, Submission, } from "./utils";
3
2
  export { AbortedDeferredError, ErrorResponse, defer, generatePath, getToPathname, isRouteErrorResponse, joinPaths, json, matchPath, matchRoutes, normalizePathname, redirect, resolvePath, resolveTo, stripBasename, warning, } from "./utils";
4
3
  export type { BrowserHistory, BrowserHistoryOptions, HashHistory, HashHistoryOptions, History, InitialEntry, Location, MemoryHistory, MemoryHistoryOptions, Path, To, } from "./history";
5
4
  export { Action, createBrowserHistory, createPath, createHashHistory, createMemoryHistory, invariant, parsePath, } from "./history";
6
5
  export * from "./router";
7
6
  /** @internal */
8
- export { convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes, getPathContributingMatches as UNSAFE_getPathContributingMatches, };
7
+ export { DeferredData as UNSAFE_DeferredData, convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes, getPathContributingMatches as UNSAFE_getPathContributingMatches, } from "./utils";
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @remix-run/router v1.2.1
2
+ * @remix-run/router v1.3.0-pre.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -96,6 +96,10 @@ function createMemoryHistory(options) {
96
96
  return location;
97
97
  }
98
98
 
99
+ function createHref(to) {
100
+ return typeof to === "string" ? to : createPath(to);
101
+ }
102
+
99
103
  let history = {
100
104
  get index() {
101
105
  return index;
@@ -109,8 +113,10 @@ function createMemoryHistory(options) {
109
113
  return getCurrentLocation();
110
114
  },
111
115
 
112
- createHref(to) {
113
- return typeof to === "string" ? to : createPath(to);
116
+ createHref,
117
+
118
+ createURL(to) {
119
+ return new URL(createHref(to), "http://localhost");
114
120
  },
115
121
 
116
122
  encodeLocation(to) {
@@ -389,15 +395,6 @@ function parsePath(path) {
389
395
 
390
396
  return parsedPath;
391
397
  }
392
- function createClientSideURL(location) {
393
- // window.location.origin is "null" (the literal string value) in Firefox
394
- // under certain conditions, notably when serving from a local HTML file
395
- // See https://bugzilla.mozilla.org/show_bug.cgi?id=878297
396
- let base = typeof window !== "undefined" && typeof window.location !== "undefined" && window.location.origin !== "null" ? window.location.origin : window.location.href;
397
- let href = typeof location === "string" ? location : createPath(location);
398
- invariant(base, "No window.location.(origin|href) available to create URL for href: " + href);
399
- return new URL(href, base);
400
- }
401
398
 
402
399
  function getUrlBasedHistory(getLocation, createHref, validateLocation, options) {
403
400
  if (options === void 0) {
@@ -462,6 +459,16 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
462
459
  }
463
460
  }
464
461
 
462
+ function createURL(to) {
463
+ // window.location.origin is "null" (the literal string value) in Firefox
464
+ // under certain conditions, notably when serving from a local HTML file
465
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=878297
466
+ let base = window.location.origin !== "null" ? window.location.origin : window.location.href;
467
+ let href = typeof to === "string" ? to : createPath(to);
468
+ invariant(base, "No window.location.(origin|href) available to create URL for href: " + href);
469
+ return new URL(href, base);
470
+ }
471
+
465
472
  let history = {
466
473
  get action() {
467
474
  return action;
@@ -488,9 +495,11 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
488
495
  return createHref(window, to);
489
496
  },
490
497
 
498
+ createURL,
499
+
491
500
  encodeLocation(to) {
492
501
  // Encode a Location the same way window.location would
493
- let url = createClientSideURL(typeof to === "string" ? to : createPath(to));
502
+ let url = createURL(to);
494
503
  return {
495
504
  pathname: url.pathname,
496
505
  search: url.search,
@@ -807,13 +816,32 @@ function generatePath(originalPath, params) {
807
816
  path = path.replace(/\*$/, "/*");
808
817
  }
809
818
 
810
- return path.replace(/^:(\w+)/g, (_, key) => {
811
- invariant(params[key] != null, "Missing \":" + key + "\" param");
812
- return params[key];
813
- }).replace(/\/:(\w+)/g, (_, key) => {
814
- invariant(params[key] != null, "Missing \":" + key + "\" param");
815
- return "/" + params[key];
816
- }).replace(/(\/?)\*/, (_, prefix, __, str) => {
819
+ return path.replace(/^:(\w+)(\??)/g, (_, key, optional) => {
820
+ let param = params[key];
821
+
822
+ if (optional === "?") {
823
+ return param == null ? "" : param;
824
+ }
825
+
826
+ if (param == null) {
827
+ invariant(false, "Missing \":" + key + "\" param");
828
+ }
829
+
830
+ return param;
831
+ }).replace(/\/:(\w+)(\??)/g, (_, key, optional) => {
832
+ let param = params[key];
833
+
834
+ if (optional === "?") {
835
+ return param == null ? "" : "/" + param;
836
+ }
837
+
838
+ if (param == null) {
839
+ invariant(false, "Missing \":" + key + "\" param");
840
+ }
841
+
842
+ return "/" + param;
843
+ }) // Remove any optional markers from optional static segments
844
+ .replace(/\?/g, "").replace(/(\/?)\*/, (_, prefix, __, str) => {
817
845
  const star = "*";
818
846
 
819
847
  if (params[star] == null) {
@@ -1160,9 +1188,10 @@ const json = function json(data, init) {
1160
1188
  };
1161
1189
  class AbortedDeferredError extends Error {}
1162
1190
  class DeferredData {
1163
- constructor(data) {
1164
- this.pendingKeys = new Set();
1165
- this.subscriber = undefined;
1191
+ constructor(data, responseInit) {
1192
+ this.pendingKeysSet = new Set();
1193
+ this.subscribers = new Set();
1194
+ this.deferredKeys = [];
1166
1195
  invariant(data && typeof data === "object" && !Array.isArray(data), "defer() only accepts plain objects"); // Set up an AbortController + Promise we can race against to exit early
1167
1196
  // cancellation
1168
1197
 
@@ -1181,6 +1210,7 @@ class DeferredData {
1181
1210
  [key]: this.trackPromise(key, value)
1182
1211
  });
1183
1212
  }, {});
1213
+ this.init = responseInit;
1184
1214
  }
1185
1215
 
1186
1216
  trackPromise(key, value) {
@@ -1188,7 +1218,8 @@ class DeferredData {
1188
1218
  return value;
1189
1219
  }
1190
1220
 
1191
- this.pendingKeys.add(key); // We store a little wrapper promise that will be extended with
1221
+ this.deferredKeys.push(key);
1222
+ this.pendingKeysSet.add(key); // We store a little wrapper promise that will be extended with
1192
1223
  // _data/_error props upon resolve/reject
1193
1224
 
1194
1225
  let promise = Promise.race([value, this.abortPromise]).then(data => this.onSettle(promise, key, null, data), error => this.onSettle(promise, key, error)); // Register rejection listeners to avoid uncaught promise rejections on
@@ -1210,39 +1241,41 @@ class DeferredData {
1210
1241
  return Promise.reject(error);
1211
1242
  }
1212
1243
 
1213
- this.pendingKeys.delete(key);
1244
+ this.pendingKeysSet.delete(key);
1214
1245
 
1215
1246
  if (this.done) {
1216
1247
  // Nothing left to abort!
1217
1248
  this.unlistenAbortSignal();
1218
1249
  }
1219
1250
 
1220
- const subscriber = this.subscriber;
1221
-
1222
1251
  if (error) {
1223
1252
  Object.defineProperty(promise, "_error", {
1224
1253
  get: () => error
1225
1254
  });
1226
- subscriber && subscriber(false);
1255
+ this.emit(false, key);
1227
1256
  return Promise.reject(error);
1228
1257
  }
1229
1258
 
1230
1259
  Object.defineProperty(promise, "_data", {
1231
1260
  get: () => data
1232
1261
  });
1233
- subscriber && subscriber(false);
1262
+ this.emit(false, key);
1234
1263
  return data;
1235
1264
  }
1236
1265
 
1266
+ emit(aborted, settledKey) {
1267
+ this.subscribers.forEach(subscriber => subscriber(aborted, settledKey));
1268
+ }
1269
+
1237
1270
  subscribe(fn) {
1238
- this.subscriber = fn;
1271
+ this.subscribers.add(fn);
1272
+ return () => this.subscribers.delete(fn);
1239
1273
  }
1240
1274
 
1241
1275
  cancel() {
1242
1276
  this.controller.abort();
1243
- this.pendingKeys.forEach((v, k) => this.pendingKeys.delete(k));
1244
- let subscriber = this.subscriber;
1245
- subscriber && subscriber(true);
1277
+ this.pendingKeysSet.forEach((v, k) => this.pendingKeysSet.delete(k));
1278
+ this.emit(true);
1246
1279
  }
1247
1280
 
1248
1281
  async resolveData(signal) {
@@ -1267,7 +1300,7 @@ class DeferredData {
1267
1300
  }
1268
1301
 
1269
1302
  get done() {
1270
- return this.pendingKeys.size === 0;
1303
+ return this.pendingKeysSet.size === 0;
1271
1304
  }
1272
1305
 
1273
1306
  get unwrappedData() {
@@ -1280,6 +1313,10 @@ class DeferredData {
1280
1313
  }, {});
1281
1314
  }
1282
1315
 
1316
+ get pendingKeys() {
1317
+ return Array.from(this.pendingKeysSet);
1318
+ }
1319
+
1283
1320
  }
1284
1321
 
1285
1322
  function isTrackedPromise(value) {
@@ -1298,9 +1335,16 @@ function unwrapTrackedPromise(value) {
1298
1335
  return value._data;
1299
1336
  }
1300
1337
 
1301
- function defer(data) {
1302
- return new DeferredData(data);
1303
- }
1338
+ const defer = function defer(data, init) {
1339
+ if (init === void 0) {
1340
+ init = {};
1341
+ }
1342
+
1343
+ let responseInit = typeof init === "number" ? {
1344
+ status: init
1345
+ } : init;
1346
+ return new DeferredData(data, responseInit);
1347
+ };
1304
1348
 
1305
1349
  /**
1306
1350
  * A redirect response. Sets the status code and the `Location` header.
@@ -1726,7 +1770,7 @@ function createRouter(init) {
1726
1770
 
1727
1771
 
1728
1772
  pendingNavigationController = new AbortController();
1729
- let request = createClientSideRequest(location, pendingNavigationController.signal, opts && opts.submission);
1773
+ let request = createClientSideRequest(init.history, location, pendingNavigationController.signal, opts && opts.submission);
1730
1774
  let pendingActionData;
1731
1775
  let pendingError;
1732
1776
 
@@ -1867,7 +1911,9 @@ function createRouter(init) {
1867
1911
  }
1868
1912
 
1869
1913
  if (isDeferredResult(result)) {
1870
- throw new Error("defer() is not supported in actions");
1914
+ throw getInternalRouterError(400, {
1915
+ type: "defer-action"
1916
+ });
1871
1917
  }
1872
1918
 
1873
1919
  return {
@@ -1904,7 +1950,7 @@ function createRouter(init) {
1904
1950
  formData: loadingNavigation.formData,
1905
1951
  formEncType: loadingNavigation.formEncType
1906
1952
  } : undefined;
1907
- let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(state, matches, activeSubmission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, pendingActionData, pendingError, fetchLoadMatches); // Cancel pending deferreds for no-longer-matched routes or routes we're
1953
+ let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, activeSubmission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, pendingActionData, pendingError, fetchLoadMatches); // Cancel pending deferreds for no-longer-matched routes or routes we're
1908
1954
  // about to reload. Note that if this is an action reload we would have
1909
1955
  // already cancelled all pending deferreds so this would be a no-op
1910
1956
 
@@ -2086,7 +2132,7 @@ function createRouter(init) {
2086
2132
  }); // Call the action for the fetcher
2087
2133
 
2088
2134
  let abortController = new AbortController();
2089
- let fetchRequest = createClientSideRequest(path, abortController.signal, submission);
2135
+ let fetchRequest = createClientSideRequest(init.history, path, abortController.signal, submission);
2090
2136
  fetchControllers.set(key, abortController);
2091
2137
  let actionResult = await callLoaderOrAction("action", fetchRequest, match, requestMatches, router.basename);
2092
2138
 
@@ -2127,13 +2173,15 @@ function createRouter(init) {
2127
2173
  }
2128
2174
 
2129
2175
  if (isDeferredResult(actionResult)) {
2130
- invariant(false, "defer() is not supported in actions");
2176
+ throw getInternalRouterError(400, {
2177
+ type: "defer-action"
2178
+ });
2131
2179
  } // Start the data load for current matches, or the next location if we're
2132
2180
  // in the middle of a navigation
2133
2181
 
2134
2182
 
2135
2183
  let nextLocation = state.navigation.location || state.location;
2136
- let revalidationRequest = createClientSideRequest(nextLocation, abortController.signal);
2184
+ let revalidationRequest = createClientSideRequest(init.history, nextLocation, abortController.signal);
2137
2185
  let matches = state.navigation.state !== "idle" ? matchRoutes(dataRoutes, state.navigation.location, init.basename) : state.matches;
2138
2186
  invariant(matches, "Didn't find any matches after fetcher action");
2139
2187
  let loadId = ++incrementingLoadId;
@@ -2147,7 +2195,7 @@ function createRouter(init) {
2147
2195
  });
2148
2196
 
2149
2197
  state.fetchers.set(key, loadFetcher);
2150
- let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, {
2198
+ let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, {
2151
2199
  [match.route.id]: actionResult.data
2152
2200
  }, undefined, // No need to send through errors since we short circuit above
2153
2201
  fetchLoadMatches); // Put all revalidating fetchers into the loading state, except for the
@@ -2260,9 +2308,9 @@ function createRouter(init) {
2260
2308
  }); // Call the loader for this fetcher route match
2261
2309
 
2262
2310
  let abortController = new AbortController();
2263
- let fetchRequest = createClientSideRequest(path, abortController.signal);
2311
+ let fetchRequest = createClientSideRequest(init.history, path, abortController.signal);
2264
2312
  fetchControllers.set(key, abortController);
2265
- let result = await callLoaderOrAction("loader", fetchRequest, match, matches, router.basename); // Deferred isn't supported or fetcher loads, await everything and treat it
2313
+ let result = await callLoaderOrAction("loader", fetchRequest, match, matches, router.basename); // Deferred isn't supported for fetcher loads, await everything and treat it
2266
2314
  // as a normal load. resolveDeferredData will return undefined if this
2267
2315
  // fetcher gets aborted, so we just leave result untouched and short circuit
2268
2316
  // below if that happens
@@ -2362,7 +2410,7 @@ function createRouter(init) {
2362
2410
  invariant(redirectLocation, "Expected a location on the redirect navigation"); // Check if this an external redirect that goes to a new origin
2363
2411
 
2364
2412
  if (typeof ((_window = window) == null ? void 0 : _window.location) !== "undefined") {
2365
- let newOrigin = createClientSideURL(redirect.location).origin;
2413
+ let newOrigin = init.history.createURL(redirect.location).origin;
2366
2414
 
2367
2415
  if (window.location.origin !== newOrigin) {
2368
2416
  if (replace) {
@@ -2428,7 +2476,7 @@ function createRouter(init) {
2428
2476
  // accordingly
2429
2477
  let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, router.basename)), ...fetchersToLoad.map(_ref8 => {
2430
2478
  let [, href, match, fetchMatches] = _ref8;
2431
- return callLoaderOrAction("loader", createClientSideRequest(href, request.signal), match, fetchMatches, router.basename);
2479
+ return callLoaderOrAction("loader", createClientSideRequest(init.history, href, request.signal), match, fetchMatches, router.basename);
2432
2480
  })]);
2433
2481
  let loaderResults = results.slice(0, matchesToLoad.length);
2434
2482
  let fetcherResults = results.slice(matchesToLoad.length);
@@ -2637,6 +2685,7 @@ function createRouter(init) {
2637
2685
  //#region createStaticHandler
2638
2686
  ////////////////////////////////////////////////////////////////////////////////
2639
2687
 
2688
+ const UNSAFE_DEFERRED_SYMBOL = Symbol("deferred");
2640
2689
  function createStaticHandler(routes, opts) {
2641
2690
  invariant(routes.length > 0, "You must provide a non-empty routes array to createStaticHandler");
2642
2691
  let dataRoutes = convertRoutesToDataRoutes(routes);
@@ -2689,7 +2738,8 @@ function createStaticHandler(routes, opts) {
2689
2738
  },
2690
2739
  statusCode: error.status,
2691
2740
  loaderHeaders: {},
2692
- actionHeaders: {}
2741
+ actionHeaders: {},
2742
+ activeDeferreds: null
2693
2743
  };
2694
2744
  } else if (!matches) {
2695
2745
  let error = getInternalRouterError(404, {
@@ -2710,7 +2760,8 @@ function createStaticHandler(routes, opts) {
2710
2760
  },
2711
2761
  statusCode: error.status,
2712
2762
  loaderHeaders: {},
2713
- actionHeaders: {}
2763
+ actionHeaders: {},
2764
+ activeDeferreds: null
2714
2765
  };
2715
2766
  }
2716
2767
 
@@ -2801,8 +2852,23 @@ function createStaticHandler(routes, opts) {
2801
2852
  } // Pick off the right state value to return
2802
2853
 
2803
2854
 
2804
- let routeData = [result.actionData, result.loaderData].find(v => v);
2805
- return Object.values(routeData || {})[0];
2855
+ if (result.actionData) {
2856
+ return Object.values(result.actionData)[0];
2857
+ }
2858
+
2859
+ if (result.loaderData) {
2860
+ var _result$activeDeferre;
2861
+
2862
+ let data = Object.values(result.loaderData)[0];
2863
+
2864
+ if ((_result$activeDeferre = result.activeDeferreds) != null && _result$activeDeferre[match.route.id]) {
2865
+ data[UNSAFE_DEFERRED_SYMBOL] = result.activeDeferreds[match.route.id];
2866
+ }
2867
+
2868
+ return data;
2869
+ }
2870
+
2871
+ return undefined;
2806
2872
  }
2807
2873
 
2808
2874
  async function queryImpl(request, location, matches, requestContext, routeMatch) {
@@ -2882,7 +2948,18 @@ function createStaticHandler(routes, opts) {
2882
2948
  }
2883
2949
 
2884
2950
  if (isDeferredResult(result)) {
2885
- throw new Error("defer() is not supported in actions");
2951
+ let error = getInternalRouterError(400, {
2952
+ type: "defer-action"
2953
+ });
2954
+
2955
+ if (isRouteRequest) {
2956
+ throw error;
2957
+ }
2958
+
2959
+ result = {
2960
+ type: ResultType.error,
2961
+ error
2962
+ };
2886
2963
  }
2887
2964
 
2888
2965
  if (isRouteRequest) {
@@ -2903,7 +2980,8 @@ function createStaticHandler(routes, opts) {
2903
2980
  // return the raw Response or value
2904
2981
  statusCode: 200,
2905
2982
  loaderHeaders: {},
2906
- actionHeaders: {}
2983
+ actionHeaders: {},
2984
+ activeDeferreds: null
2907
2985
  };
2908
2986
  }
2909
2987
 
@@ -2966,7 +3044,8 @@ function createStaticHandler(routes, opts) {
2966
3044
  }), {}),
2967
3045
  errors: pendingActionError || null,
2968
3046
  statusCode: 200,
2969
- loaderHeaders: {}
3047
+ loaderHeaders: {},
3048
+ activeDeferreds: null
2970
3049
  };
2971
3050
  }
2972
3051
 
@@ -2975,27 +3054,21 @@ function createStaticHandler(routes, opts) {
2975
3054
  if (request.signal.aborted) {
2976
3055
  let method = isRouteRequest ? "queryRoute" : "query";
2977
3056
  throw new Error(method + "() call aborted");
2978
- }
3057
+ } // Process and commit output from loaders
2979
3058
 
2980
- let executedLoaders = new Set();
2981
- results.forEach((result, i) => {
2982
- executedLoaders.add(matchesToLoad[i].route.id); // Can't do anything with these without the Remix side of things, so just
2983
- // cancel them for now
2984
3059
 
2985
- if (isDeferredResult(result)) {
2986
- result.deferredData.cancel();
2987
- }
2988
- }); // Process and commit output from loaders
2989
-
2990
- let context = processRouteLoaderData(matches, matchesToLoad, results, pendingActionError); // Add a null for any non-loader matches for proper revalidation on the client
3060
+ let activeDeferreds = new Map();
3061
+ let context = processRouteLoaderData(matches, matchesToLoad, results, pendingActionError, activeDeferreds); // Add a null for any non-loader matches for proper revalidation on the client
2991
3062
 
3063
+ let executedLoaders = new Set(matchesToLoad.map(match => match.route.id));
2992
3064
  matches.forEach(match => {
2993
3065
  if (!executedLoaders.has(match.route.id)) {
2994
3066
  context.loaderData[match.route.id] = null;
2995
3067
  }
2996
3068
  });
2997
3069
  return _extends({}, context, {
2998
- matches
3070
+ matches,
3071
+ activeDeferreds: activeDeferreds.size > 0 ? Object.fromEntries(activeDeferreds.entries()) : null
2999
3072
  });
3000
3073
  }
3001
3074
 
@@ -3114,13 +3187,13 @@ function getLoaderMatchesUntilBoundary(matches, boundaryId) {
3114
3187
  return boundaryMatches;
3115
3188
  }
3116
3189
 
3117
- function getMatchesToLoad(state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, pendingActionData, pendingError, fetchLoadMatches) {
3190
+ function getMatchesToLoad(history, state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, pendingActionData, pendingError, fetchLoadMatches) {
3118
3191
  let actionResult = pendingError ? Object.values(pendingError)[0] : pendingActionData ? Object.values(pendingActionData)[0] : undefined; // Pick navigation matches that are net-new or qualify for revalidation
3119
3192
 
3120
3193
  let boundaryId = pendingError ? Object.keys(pendingError)[0] : undefined;
3121
3194
  let boundaryMatches = getLoaderMatchesUntilBoundary(matches, boundaryId);
3122
3195
  let navigationMatches = boundaryMatches.filter((match, index) => match.route.loader != null && (isNewLoader(state.loaderData, state.matches[index], match) || // If this route had a pending deferred cancelled it must be revalidated
3123
- cancelledDeferredRoutes.some(id => id === match.route.id) || shouldRevalidateLoader(state.location, state.matches[index], submission, location, match, isRevalidationRequired, actionResult))); // Pick fetcher.loads that need to be revalidated
3196
+ cancelledDeferredRoutes.some(id => id === match.route.id) || shouldRevalidateLoader(history, state.location, state.matches[index], submission, location, match, isRevalidationRequired, actionResult))); // Pick fetcher.loads that need to be revalidated
3124
3197
 
3125
3198
  let revalidatingFetchers = [];
3126
3199
  fetchLoadMatches && fetchLoadMatches.forEach((_ref10, key) => {
@@ -3130,7 +3203,7 @@ function getMatchesToLoad(state, matches, submission, location, isRevalidationRe
3130
3203
  if (cancelledFetcherLoads.includes(key)) {
3131
3204
  revalidatingFetchers.push([key, href, match, fetchMatches]);
3132
3205
  } else if (isRevalidationRequired) {
3133
- let shouldRevalidate = shouldRevalidateLoader(href, match, submission, href, match, isRevalidationRequired, actionResult);
3206
+ let shouldRevalidate = shouldRevalidateLoader(history, href, match, submission, href, match, isRevalidationRequired, actionResult);
3134
3207
 
3135
3208
  if (shouldRevalidate) {
3136
3209
  revalidatingFetchers.push([key, href, match, fetchMatches]);
@@ -3160,10 +3233,10 @@ function isNewRouteInstance(currentMatch, match) {
3160
3233
  );
3161
3234
  }
3162
3235
 
3163
- function shouldRevalidateLoader(currentLocation, currentMatch, submission, location, match, isRevalidationRequired, actionResult) {
3164
- let currentUrl = createClientSideURL(currentLocation);
3236
+ function shouldRevalidateLoader(history, currentLocation, currentMatch, submission, location, match, isRevalidationRequired, actionResult) {
3237
+ let currentUrl = history.createURL(currentLocation);
3165
3238
  let currentParams = currentMatch.params;
3166
- let nextUrl = createClientSideURL(location);
3239
+ let nextUrl = history.createURL(location);
3167
3240
  let nextParams = match.params; // This is the default implementation as to when we revalidate. If the route
3168
3241
  // provides it's own implementation, then we give them full control but
3169
3242
  // provide this value so they can leverage it if needed after they check
@@ -3240,7 +3313,7 @@ async function callLoaderOrAction(type, request, match, matches, basename, isSta
3240
3313
  if (redirectStatusCodes.has(status)) {
3241
3314
  let location = result.headers.get("Location");
3242
3315
  invariant(location, "Redirects returned/thrown from loaders/actions must have a Location header");
3243
- let isAbsolute = /^[a-z+]+:\/\//i.test(location) || location.startsWith("//"); // Support relative routing in internal redirects
3316
+ let isAbsolute = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(location); // Support relative routing in internal redirects
3244
3317
 
3245
3318
  if (!isAbsolute) {
3246
3319
  let activeMatches = matches.slice(0, matches.indexOf(match) + 1);
@@ -3333,8 +3406,8 @@ async function callLoaderOrAction(type, request, match, matches, basename, isSta
3333
3406
  // Request instance from the static handler (query/queryRoute)
3334
3407
 
3335
3408
 
3336
- function createClientSideRequest(location, signal, submission) {
3337
- let url = createClientSideURL(stripHashFromPath(location)).toString();
3409
+ function createClientSideRequest(history, location, signal, submission) {
3410
+ let url = history.createURL(stripHashFromPath(location)).toString();
3338
3411
  let init = {
3339
3412
  signal
3340
3413
  };
@@ -3407,13 +3480,16 @@ function processRouteLoaderData(matches, matchesToLoad, results, pendingError, a
3407
3480
  if (result.headers) {
3408
3481
  loaderHeaders[id] = result.headers;
3409
3482
  }
3410
- } else if (isDeferredResult(result)) {
3411
- activeDeferreds && activeDeferreds.set(id, result.deferredData);
3412
- loaderData[id] = result.deferredData.data; // TODO: Add statusCode/headers once we wire up streaming in Remix
3413
3483
  } else {
3414
- loaderData[id] = result.data; // Error status codes always override success status codes, but if all
3484
+ if (isDeferredResult(result)) {
3485
+ activeDeferreds.set(id, result.deferredData);
3486
+ loaderData[id] = result.deferredData.data;
3487
+ } else {
3488
+ loaderData[id] = result.data;
3489
+ } // Error status codes always override success status codes, but if all
3415
3490
  // loaders are successful we take the deepest status code.
3416
3491
 
3492
+
3417
3493
  if (result.statusCode != null && result.statusCode !== 200 && !foundError) {
3418
3494
  statusCode = result.statusCode;
3419
3495
  }
@@ -3463,11 +3539,11 @@ function processLoaderData(state, matches, matchesToLoad, results, pendingError,
3463
3539
  } else if (isRedirectResult(result)) {
3464
3540
  // Should never get here, redirects should get processed above, but we
3465
3541
  // keep this to type narrow to a success result in the else
3466
- throw new Error("Unhandled fetcher revalidation redirect");
3542
+ invariant(false, "Unhandled fetcher revalidation redirect");
3467
3543
  } else if (isDeferredResult(result)) {
3468
3544
  // Should never get here, deferred data should be awaited for fetchers
3469
3545
  // in resolveDeferredResults
3470
- throw new Error("Unhandled fetcher deferred data");
3546
+ invariant(false, "Unhandled fetcher deferred data");
3471
3547
  } else {
3472
3548
  let doneFetcher = {
3473
3549
  state: "idle",
@@ -3539,7 +3615,8 @@ function getInternalRouterError(status, _temp4) {
3539
3615
  let {
3540
3616
  pathname,
3541
3617
  routeId,
3542
- method
3618
+ method,
3619
+ type
3543
3620
  } = _temp4 === void 0 ? {} : _temp4;
3544
3621
  let statusText = "Unknown Server Error";
3545
3622
  let errorMessage = "Unknown @remix-run/router error";
@@ -3549,6 +3626,8 @@ function getInternalRouterError(status, _temp4) {
3549
3626
 
3550
3627
  if (method && pathname && routeId) {
3551
3628
  errorMessage = "You made a " + method + " request to \"" + pathname + "\" but " + ("did not provide a `loader` for route \"" + routeId + "\", ") + "so there is no way to handle the request.";
3629
+ } else if (type === "defer-action") {
3630
+ errorMessage = "defer() is not supported in actions";
3552
3631
  } else {
3553
3632
  errorMessage = "Cannot submit binary form data using GET";
3554
3633
  }
@@ -3722,6 +3801,8 @@ exports.AbortedDeferredError = AbortedDeferredError;
3722
3801
  exports.ErrorResponse = ErrorResponse;
3723
3802
  exports.IDLE_FETCHER = IDLE_FETCHER;
3724
3803
  exports.IDLE_NAVIGATION = IDLE_NAVIGATION;
3804
+ exports.UNSAFE_DEFERRED_SYMBOL = UNSAFE_DEFERRED_SYMBOL;
3805
+ exports.UNSAFE_DeferredData = DeferredData;
3725
3806
  exports.UNSAFE_convertRoutesToDataRoutes = convertRoutesToDataRoutes;
3726
3807
  exports.UNSAFE_getPathContributingMatches = getPathContributingMatches;
3727
3808
  exports.createBrowserHistory = createBrowserHistory;