@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/dist/router.d.ts CHANGED
@@ -229,6 +229,7 @@ export interface StaticHandlerContext {
229
229
  statusCode: number;
230
230
  loaderHeaders: Record<string, Headers>;
231
231
  actionHeaders: Record<string, Headers>;
232
+ activeDeferreds: Record<string, DeferredData> | null;
232
233
  _deepestRenderedBoundaryId?: string | null;
233
234
  }
234
235
  /**
@@ -366,6 +367,7 @@ export declare const IDLE_FETCHER: FetcherStates["Idle"];
366
367
  * Create a router and listen to history POP navigations
367
368
  */
368
369
  export declare function createRouter(init: RouterInit): Router;
370
+ export declare const UNSAFE_DEFERRED_SYMBOL: unique symbol;
369
371
  export declare function createStaticHandler(routes: AgnosticRouteObject[], opts?: {
370
372
  basename?: string;
371
373
  }): StaticHandler;
package/dist/router.js CHANGED
@@ -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
  *
@@ -99,6 +99,10 @@ function createMemoryHistory(options) {
99
99
  return location;
100
100
  }
101
101
 
102
+ function createHref(to) {
103
+ return typeof to === "string" ? to : createPath(to);
104
+ }
105
+
102
106
  let history = {
103
107
  get index() {
104
108
  return index;
@@ -112,8 +116,10 @@ function createMemoryHistory(options) {
112
116
  return getCurrentLocation();
113
117
  },
114
118
 
115
- createHref(to) {
116
- return typeof to === "string" ? to : createPath(to);
119
+ createHref,
120
+
121
+ createURL(to) {
122
+ return new URL(createHref(to), "http://localhost");
117
123
  },
118
124
 
119
125
  encodeLocation(to) {
@@ -358,15 +364,6 @@ function parsePath(path) {
358
364
 
359
365
  return parsedPath;
360
366
  }
361
- function createClientSideURL(location) {
362
- // window.location.origin is "null" (the literal string value) in Firefox
363
- // under certain conditions, notably when serving from a local HTML file
364
- // See https://bugzilla.mozilla.org/show_bug.cgi?id=878297
365
- let base = typeof window !== "undefined" && typeof window.location !== "undefined" && window.location.origin !== "null" ? window.location.origin : window.location.href;
366
- let href = typeof location === "string" ? location : createPath(location);
367
- invariant(base, "No window.location.(origin|href) available to create URL for href: " + href);
368
- return new URL(href, base);
369
- }
370
367
 
371
368
  function getUrlBasedHistory(getLocation, createHref, validateLocation, options) {
372
369
  if (options === void 0) {
@@ -431,6 +428,16 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
431
428
  }
432
429
  }
433
430
 
431
+ function createURL(to) {
432
+ // window.location.origin is "null" (the literal string value) in Firefox
433
+ // under certain conditions, notably when serving from a local HTML file
434
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=878297
435
+ let base = window.location.origin !== "null" ? window.location.origin : window.location.href;
436
+ let href = typeof to === "string" ? to : createPath(to);
437
+ invariant(base, "No window.location.(origin|href) available to create URL for href: " + href);
438
+ return new URL(href, base);
439
+ }
440
+
434
441
  let history = {
435
442
  get action() {
436
443
  return action;
@@ -457,9 +464,11 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
457
464
  return createHref(window, to);
458
465
  },
459
466
 
467
+ createURL,
468
+
460
469
  encodeLocation(to) {
461
470
  // Encode a Location the same way window.location would
462
- let url = createClientSideURL(typeof to === "string" ? to : createPath(to));
471
+ let url = createURL(to);
463
472
  return {
464
473
  pathname: url.pathname,
465
474
  search: url.search,
@@ -769,13 +778,32 @@ function generatePath(originalPath, params) {
769
778
  path = path.replace(/\*$/, "/*");
770
779
  }
771
780
 
772
- return path.replace(/^:(\w+)/g, (_, key) => {
773
- invariant(params[key] != null, "Missing \":" + key + "\" param");
774
- return params[key];
775
- }).replace(/\/:(\w+)/g, (_, key) => {
776
- invariant(params[key] != null, "Missing \":" + key + "\" param");
777
- return "/" + params[key];
778
- }).replace(/(\/?)\*/, (_, prefix, __, str) => {
781
+ return path.replace(/^:(\w+)(\??)/g, (_, key, optional) => {
782
+ let param = params[key];
783
+
784
+ if (optional === "?") {
785
+ return param == null ? "" : param;
786
+ }
787
+
788
+ if (param == null) {
789
+ invariant(false, "Missing \":" + key + "\" param");
790
+ }
791
+
792
+ return param;
793
+ }).replace(/\/:(\w+)(\??)/g, (_, key, optional) => {
794
+ let param = params[key];
795
+
796
+ if (optional === "?") {
797
+ return param == null ? "" : "/" + param;
798
+ }
799
+
800
+ if (param == null) {
801
+ invariant(false, "Missing \":" + key + "\" param");
802
+ }
803
+
804
+ return "/" + param;
805
+ }) // Remove any optional markers from optional static segments
806
+ .replace(/\?/g, "").replace(/(\/?)\*/, (_, prefix, __, str) => {
779
807
  const star = "*";
780
808
 
781
809
  if (params[star] == null) {
@@ -1119,9 +1147,10 @@ const json = function json(data, init) {
1119
1147
  };
1120
1148
  class AbortedDeferredError extends Error {}
1121
1149
  class DeferredData {
1122
- constructor(data) {
1123
- this.pendingKeys = new Set();
1124
- this.subscriber = undefined;
1150
+ constructor(data, responseInit) {
1151
+ this.pendingKeysSet = new Set();
1152
+ this.subscribers = new Set();
1153
+ this.deferredKeys = [];
1125
1154
  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
1126
1155
  // cancellation
1127
1156
 
@@ -1140,6 +1169,7 @@ class DeferredData {
1140
1169
  [key]: this.trackPromise(key, value)
1141
1170
  });
1142
1171
  }, {});
1172
+ this.init = responseInit;
1143
1173
  }
1144
1174
 
1145
1175
  trackPromise(key, value) {
@@ -1147,7 +1177,8 @@ class DeferredData {
1147
1177
  return value;
1148
1178
  }
1149
1179
 
1150
- this.pendingKeys.add(key); // We store a little wrapper promise that will be extended with
1180
+ this.deferredKeys.push(key);
1181
+ this.pendingKeysSet.add(key); // We store a little wrapper promise that will be extended with
1151
1182
  // _data/_error props upon resolve/reject
1152
1183
 
1153
1184
  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
@@ -1169,39 +1200,41 @@ class DeferredData {
1169
1200
  return Promise.reject(error);
1170
1201
  }
1171
1202
 
1172
- this.pendingKeys.delete(key);
1203
+ this.pendingKeysSet.delete(key);
1173
1204
 
1174
1205
  if (this.done) {
1175
1206
  // Nothing left to abort!
1176
1207
  this.unlistenAbortSignal();
1177
1208
  }
1178
1209
 
1179
- const subscriber = this.subscriber;
1180
-
1181
1210
  if (error) {
1182
1211
  Object.defineProperty(promise, "_error", {
1183
1212
  get: () => error
1184
1213
  });
1185
- subscriber && subscriber(false);
1214
+ this.emit(false, key);
1186
1215
  return Promise.reject(error);
1187
1216
  }
1188
1217
 
1189
1218
  Object.defineProperty(promise, "_data", {
1190
1219
  get: () => data
1191
1220
  });
1192
- subscriber && subscriber(false);
1221
+ this.emit(false, key);
1193
1222
  return data;
1194
1223
  }
1195
1224
 
1225
+ emit(aborted, settledKey) {
1226
+ this.subscribers.forEach(subscriber => subscriber(aborted, settledKey));
1227
+ }
1228
+
1196
1229
  subscribe(fn) {
1197
- this.subscriber = fn;
1230
+ this.subscribers.add(fn);
1231
+ return () => this.subscribers.delete(fn);
1198
1232
  }
1199
1233
 
1200
1234
  cancel() {
1201
1235
  this.controller.abort();
1202
- this.pendingKeys.forEach((v, k) => this.pendingKeys.delete(k));
1203
- let subscriber = this.subscriber;
1204
- subscriber && subscriber(true);
1236
+ this.pendingKeysSet.forEach((v, k) => this.pendingKeysSet.delete(k));
1237
+ this.emit(true);
1205
1238
  }
1206
1239
 
1207
1240
  async resolveData(signal) {
@@ -1226,7 +1259,7 @@ class DeferredData {
1226
1259
  }
1227
1260
 
1228
1261
  get done() {
1229
- return this.pendingKeys.size === 0;
1262
+ return this.pendingKeysSet.size === 0;
1230
1263
  }
1231
1264
 
1232
1265
  get unwrappedData() {
@@ -1239,6 +1272,10 @@ class DeferredData {
1239
1272
  }, {});
1240
1273
  }
1241
1274
 
1275
+ get pendingKeys() {
1276
+ return Array.from(this.pendingKeysSet);
1277
+ }
1278
+
1242
1279
  }
1243
1280
 
1244
1281
  function isTrackedPromise(value) {
@@ -1257,9 +1294,16 @@ function unwrapTrackedPromise(value) {
1257
1294
  return value._data;
1258
1295
  }
1259
1296
 
1260
- function defer(data) {
1261
- return new DeferredData(data);
1262
- }
1297
+ const defer = function defer(data, init) {
1298
+ if (init === void 0) {
1299
+ init = {};
1300
+ }
1301
+
1302
+ let responseInit = typeof init === "number" ? {
1303
+ status: init
1304
+ } : init;
1305
+ return new DeferredData(data, responseInit);
1306
+ };
1263
1307
  /**
1264
1308
  * A redirect response. Sets the status code and the `Location` header.
1265
1309
  * Defaults to "302 Found".
@@ -1677,7 +1721,7 @@ function createRouter(init) {
1677
1721
 
1678
1722
 
1679
1723
  pendingNavigationController = new AbortController();
1680
- let request = createClientSideRequest(location, pendingNavigationController.signal, opts && opts.submission);
1724
+ let request = createClientSideRequest(init.history, location, pendingNavigationController.signal, opts && opts.submission);
1681
1725
  let pendingActionData;
1682
1726
  let pendingError;
1683
1727
 
@@ -1818,7 +1862,9 @@ function createRouter(init) {
1818
1862
  }
1819
1863
 
1820
1864
  if (isDeferredResult(result)) {
1821
- throw new Error("defer() is not supported in actions");
1865
+ throw getInternalRouterError(400, {
1866
+ type: "defer-action"
1867
+ });
1822
1868
  }
1823
1869
 
1824
1870
  return {
@@ -1855,7 +1901,7 @@ function createRouter(init) {
1855
1901
  formData: loadingNavigation.formData,
1856
1902
  formEncType: loadingNavigation.formEncType
1857
1903
  } : undefined;
1858
- 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
1904
+ 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
1859
1905
  // about to reload. Note that if this is an action reload we would have
1860
1906
  // already cancelled all pending deferreds so this would be a no-op
1861
1907
 
@@ -2037,7 +2083,7 @@ function createRouter(init) {
2037
2083
  }); // Call the action for the fetcher
2038
2084
 
2039
2085
  let abortController = new AbortController();
2040
- let fetchRequest = createClientSideRequest(path, abortController.signal, submission);
2086
+ let fetchRequest = createClientSideRequest(init.history, path, abortController.signal, submission);
2041
2087
  fetchControllers.set(key, abortController);
2042
2088
  let actionResult = await callLoaderOrAction("action", fetchRequest, match, requestMatches, router.basename);
2043
2089
 
@@ -2078,13 +2124,15 @@ function createRouter(init) {
2078
2124
  }
2079
2125
 
2080
2126
  if (isDeferredResult(actionResult)) {
2081
- invariant(false, "defer() is not supported in actions");
2127
+ throw getInternalRouterError(400, {
2128
+ type: "defer-action"
2129
+ });
2082
2130
  } // Start the data load for current matches, or the next location if we're
2083
2131
  // in the middle of a navigation
2084
2132
 
2085
2133
 
2086
2134
  let nextLocation = state.navigation.location || state.location;
2087
- let revalidationRequest = createClientSideRequest(nextLocation, abortController.signal);
2135
+ let revalidationRequest = createClientSideRequest(init.history, nextLocation, abortController.signal);
2088
2136
  let matches = state.navigation.state !== "idle" ? matchRoutes(dataRoutes, state.navigation.location, init.basename) : state.matches;
2089
2137
  invariant(matches, "Didn't find any matches after fetcher action");
2090
2138
  let loadId = ++incrementingLoadId;
@@ -2098,7 +2146,7 @@ function createRouter(init) {
2098
2146
  });
2099
2147
 
2100
2148
  state.fetchers.set(key, loadFetcher);
2101
- let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, {
2149
+ let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, {
2102
2150
  [match.route.id]: actionResult.data
2103
2151
  }, undefined, // No need to send through errors since we short circuit above
2104
2152
  fetchLoadMatches); // Put all revalidating fetchers into the loading state, except for the
@@ -2211,9 +2259,9 @@ function createRouter(init) {
2211
2259
  }); // Call the loader for this fetcher route match
2212
2260
 
2213
2261
  let abortController = new AbortController();
2214
- let fetchRequest = createClientSideRequest(path, abortController.signal);
2262
+ let fetchRequest = createClientSideRequest(init.history, path, abortController.signal);
2215
2263
  fetchControllers.set(key, abortController);
2216
- let result = await callLoaderOrAction("loader", fetchRequest, match, matches, router.basename); // Deferred isn't supported or fetcher loads, await everything and treat it
2264
+ let result = await callLoaderOrAction("loader", fetchRequest, match, matches, router.basename); // Deferred isn't supported for fetcher loads, await everything and treat it
2217
2265
  // as a normal load. resolveDeferredData will return undefined if this
2218
2266
  // fetcher gets aborted, so we just leave result untouched and short circuit
2219
2267
  // below if that happens
@@ -2313,7 +2361,7 @@ function createRouter(init) {
2313
2361
  invariant(redirectLocation, "Expected a location on the redirect navigation"); // Check if this an external redirect that goes to a new origin
2314
2362
 
2315
2363
  if (typeof ((_window = window) == null ? void 0 : _window.location) !== "undefined") {
2316
- let newOrigin = createClientSideURL(redirect.location).origin;
2364
+ let newOrigin = init.history.createURL(redirect.location).origin;
2317
2365
 
2318
2366
  if (window.location.origin !== newOrigin) {
2319
2367
  if (replace) {
@@ -2379,7 +2427,7 @@ function createRouter(init) {
2379
2427
  // accordingly
2380
2428
  let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, router.basename)), ...fetchersToLoad.map(_ref8 => {
2381
2429
  let [, href, match, fetchMatches] = _ref8;
2382
- return callLoaderOrAction("loader", createClientSideRequest(href, request.signal), match, fetchMatches, router.basename);
2430
+ return callLoaderOrAction("loader", createClientSideRequest(init.history, href, request.signal), match, fetchMatches, router.basename);
2383
2431
  })]);
2384
2432
  let loaderResults = results.slice(0, matchesToLoad.length);
2385
2433
  let fetcherResults = results.slice(matchesToLoad.length);
@@ -2588,6 +2636,7 @@ function createRouter(init) {
2588
2636
  //#region createStaticHandler
2589
2637
  ////////////////////////////////////////////////////////////////////////////////
2590
2638
 
2639
+ const UNSAFE_DEFERRED_SYMBOL = Symbol("deferred");
2591
2640
  function createStaticHandler(routes, opts) {
2592
2641
  invariant(routes.length > 0, "You must provide a non-empty routes array to createStaticHandler");
2593
2642
  let dataRoutes = convertRoutesToDataRoutes(routes);
@@ -2640,7 +2689,8 @@ function createStaticHandler(routes, opts) {
2640
2689
  },
2641
2690
  statusCode: error.status,
2642
2691
  loaderHeaders: {},
2643
- actionHeaders: {}
2692
+ actionHeaders: {},
2693
+ activeDeferreds: null
2644
2694
  };
2645
2695
  } else if (!matches) {
2646
2696
  let error = getInternalRouterError(404, {
@@ -2661,7 +2711,8 @@ function createStaticHandler(routes, opts) {
2661
2711
  },
2662
2712
  statusCode: error.status,
2663
2713
  loaderHeaders: {},
2664
- actionHeaders: {}
2714
+ actionHeaders: {},
2715
+ activeDeferreds: null
2665
2716
  };
2666
2717
  }
2667
2718
 
@@ -2752,8 +2803,23 @@ function createStaticHandler(routes, opts) {
2752
2803
  } // Pick off the right state value to return
2753
2804
 
2754
2805
 
2755
- let routeData = [result.actionData, result.loaderData].find(v => v);
2756
- return Object.values(routeData || {})[0];
2806
+ if (result.actionData) {
2807
+ return Object.values(result.actionData)[0];
2808
+ }
2809
+
2810
+ if (result.loaderData) {
2811
+ var _result$activeDeferre;
2812
+
2813
+ let data = Object.values(result.loaderData)[0];
2814
+
2815
+ if ((_result$activeDeferre = result.activeDeferreds) != null && _result$activeDeferre[match.route.id]) {
2816
+ data[UNSAFE_DEFERRED_SYMBOL] = result.activeDeferreds[match.route.id];
2817
+ }
2818
+
2819
+ return data;
2820
+ }
2821
+
2822
+ return undefined;
2757
2823
  }
2758
2824
 
2759
2825
  async function queryImpl(request, location, matches, requestContext, routeMatch) {
@@ -2833,7 +2899,18 @@ function createStaticHandler(routes, opts) {
2833
2899
  }
2834
2900
 
2835
2901
  if (isDeferredResult(result)) {
2836
- throw new Error("defer() is not supported in actions");
2902
+ let error = getInternalRouterError(400, {
2903
+ type: "defer-action"
2904
+ });
2905
+
2906
+ if (isRouteRequest) {
2907
+ throw error;
2908
+ }
2909
+
2910
+ result = {
2911
+ type: ResultType.error,
2912
+ error
2913
+ };
2837
2914
  }
2838
2915
 
2839
2916
  if (isRouteRequest) {
@@ -2854,7 +2931,8 @@ function createStaticHandler(routes, opts) {
2854
2931
  // return the raw Response or value
2855
2932
  statusCode: 200,
2856
2933
  loaderHeaders: {},
2857
- actionHeaders: {}
2934
+ actionHeaders: {},
2935
+ activeDeferreds: null
2858
2936
  };
2859
2937
  }
2860
2938
 
@@ -2917,7 +2995,8 @@ function createStaticHandler(routes, opts) {
2917
2995
  }), {}),
2918
2996
  errors: pendingActionError || null,
2919
2997
  statusCode: 200,
2920
- loaderHeaders: {}
2998
+ loaderHeaders: {},
2999
+ activeDeferreds: null
2921
3000
  };
2922
3001
  }
2923
3002
 
@@ -2926,27 +3005,21 @@ function createStaticHandler(routes, opts) {
2926
3005
  if (request.signal.aborted) {
2927
3006
  let method = isRouteRequest ? "queryRoute" : "query";
2928
3007
  throw new Error(method + "() call aborted");
2929
- }
3008
+ } // Process and commit output from loaders
2930
3009
 
2931
- let executedLoaders = new Set();
2932
- results.forEach((result, i) => {
2933
- executedLoaders.add(matchesToLoad[i].route.id); // Can't do anything with these without the Remix side of things, so just
2934
- // cancel them for now
2935
3010
 
2936
- if (isDeferredResult(result)) {
2937
- result.deferredData.cancel();
2938
- }
2939
- }); // Process and commit output from loaders
2940
-
2941
- let context = processRouteLoaderData(matches, matchesToLoad, results, pendingActionError); // Add a null for any non-loader matches for proper revalidation on the client
3011
+ let activeDeferreds = new Map();
3012
+ let context = processRouteLoaderData(matches, matchesToLoad, results, pendingActionError, activeDeferreds); // Add a null for any non-loader matches for proper revalidation on the client
2942
3013
 
3014
+ let executedLoaders = new Set(matchesToLoad.map(match => match.route.id));
2943
3015
  matches.forEach(match => {
2944
3016
  if (!executedLoaders.has(match.route.id)) {
2945
3017
  context.loaderData[match.route.id] = null;
2946
3018
  }
2947
3019
  });
2948
3020
  return _extends({}, context, {
2949
- matches
3021
+ matches,
3022
+ activeDeferreds: activeDeferreds.size > 0 ? Object.fromEntries(activeDeferreds.entries()) : null
2950
3023
  });
2951
3024
  }
2952
3025
 
@@ -3065,13 +3138,13 @@ function getLoaderMatchesUntilBoundary(matches, boundaryId) {
3065
3138
  return boundaryMatches;
3066
3139
  }
3067
3140
 
3068
- function getMatchesToLoad(state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, pendingActionData, pendingError, fetchLoadMatches) {
3141
+ function getMatchesToLoad(history, state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, pendingActionData, pendingError, fetchLoadMatches) {
3069
3142
  let actionResult = pendingError ? Object.values(pendingError)[0] : pendingActionData ? Object.values(pendingActionData)[0] : undefined; // Pick navigation matches that are net-new or qualify for revalidation
3070
3143
 
3071
3144
  let boundaryId = pendingError ? Object.keys(pendingError)[0] : undefined;
3072
3145
  let boundaryMatches = getLoaderMatchesUntilBoundary(matches, boundaryId);
3073
3146
  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
3074
- 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
3147
+ 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
3075
3148
 
3076
3149
  let revalidatingFetchers = [];
3077
3150
  fetchLoadMatches && fetchLoadMatches.forEach((_ref10, key) => {
@@ -3081,7 +3154,7 @@ function getMatchesToLoad(state, matches, submission, location, isRevalidationRe
3081
3154
  if (cancelledFetcherLoads.includes(key)) {
3082
3155
  revalidatingFetchers.push([key, href, match, fetchMatches]);
3083
3156
  } else if (isRevalidationRequired) {
3084
- let shouldRevalidate = shouldRevalidateLoader(href, match, submission, href, match, isRevalidationRequired, actionResult);
3157
+ let shouldRevalidate = shouldRevalidateLoader(history, href, match, submission, href, match, isRevalidationRequired, actionResult);
3085
3158
 
3086
3159
  if (shouldRevalidate) {
3087
3160
  revalidatingFetchers.push([key, href, match, fetchMatches]);
@@ -3111,10 +3184,10 @@ function isNewRouteInstance(currentMatch, match) {
3111
3184
  );
3112
3185
  }
3113
3186
 
3114
- function shouldRevalidateLoader(currentLocation, currentMatch, submission, location, match, isRevalidationRequired, actionResult) {
3115
- let currentUrl = createClientSideURL(currentLocation);
3187
+ function shouldRevalidateLoader(history, currentLocation, currentMatch, submission, location, match, isRevalidationRequired, actionResult) {
3188
+ let currentUrl = history.createURL(currentLocation);
3116
3189
  let currentParams = currentMatch.params;
3117
- let nextUrl = createClientSideURL(location);
3190
+ let nextUrl = history.createURL(location);
3118
3191
  let nextParams = match.params; // This is the default implementation as to when we revalidate. If the route
3119
3192
  // provides it's own implementation, then we give them full control but
3120
3193
  // provide this value so they can leverage it if needed after they check
@@ -3191,7 +3264,7 @@ async function callLoaderOrAction(type, request, match, matches, basename, isSta
3191
3264
  if (redirectStatusCodes.has(status)) {
3192
3265
  let location = result.headers.get("Location");
3193
3266
  invariant(location, "Redirects returned/thrown from loaders/actions must have a Location header");
3194
- let isAbsolute = /^[a-z+]+:\/\//i.test(location) || location.startsWith("//"); // Support relative routing in internal redirects
3267
+ let isAbsolute = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(location); // Support relative routing in internal redirects
3195
3268
 
3196
3269
  if (!isAbsolute) {
3197
3270
  let activeMatches = matches.slice(0, matches.indexOf(match) + 1);
@@ -3284,8 +3357,8 @@ async function callLoaderOrAction(type, request, match, matches, basename, isSta
3284
3357
  // Request instance from the static handler (query/queryRoute)
3285
3358
 
3286
3359
 
3287
- function createClientSideRequest(location, signal, submission) {
3288
- let url = createClientSideURL(stripHashFromPath(location)).toString();
3360
+ function createClientSideRequest(history, location, signal, submission) {
3361
+ let url = history.createURL(stripHashFromPath(location)).toString();
3289
3362
  let init = {
3290
3363
  signal
3291
3364
  };
@@ -3358,13 +3431,16 @@ function processRouteLoaderData(matches, matchesToLoad, results, pendingError, a
3358
3431
  if (result.headers) {
3359
3432
  loaderHeaders[id] = result.headers;
3360
3433
  }
3361
- } else if (isDeferredResult(result)) {
3362
- activeDeferreds && activeDeferreds.set(id, result.deferredData);
3363
- loaderData[id] = result.deferredData.data; // TODO: Add statusCode/headers once we wire up streaming in Remix
3364
3434
  } else {
3365
- loaderData[id] = result.data; // Error status codes always override success status codes, but if all
3435
+ if (isDeferredResult(result)) {
3436
+ activeDeferreds.set(id, result.deferredData);
3437
+ loaderData[id] = result.deferredData.data;
3438
+ } else {
3439
+ loaderData[id] = result.data;
3440
+ } // Error status codes always override success status codes, but if all
3366
3441
  // loaders are successful we take the deepest status code.
3367
3442
 
3443
+
3368
3444
  if (result.statusCode != null && result.statusCode !== 200 && !foundError) {
3369
3445
  statusCode = result.statusCode;
3370
3446
  }
@@ -3414,11 +3490,11 @@ function processLoaderData(state, matches, matchesToLoad, results, pendingError,
3414
3490
  } else if (isRedirectResult(result)) {
3415
3491
  // Should never get here, redirects should get processed above, but we
3416
3492
  // keep this to type narrow to a success result in the else
3417
- throw new Error("Unhandled fetcher revalidation redirect");
3493
+ invariant(false, "Unhandled fetcher revalidation redirect");
3418
3494
  } else if (isDeferredResult(result)) {
3419
3495
  // Should never get here, deferred data should be awaited for fetchers
3420
3496
  // in resolveDeferredResults
3421
- throw new Error("Unhandled fetcher deferred data");
3497
+ invariant(false, "Unhandled fetcher deferred data");
3422
3498
  } else {
3423
3499
  let doneFetcher = {
3424
3500
  state: "idle",
@@ -3490,7 +3566,8 @@ function getInternalRouterError(status, _temp4) {
3490
3566
  let {
3491
3567
  pathname,
3492
3568
  routeId,
3493
- method
3569
+ method,
3570
+ type
3494
3571
  } = _temp4 === void 0 ? {} : _temp4;
3495
3572
  let statusText = "Unknown Server Error";
3496
3573
  let errorMessage = "Unknown @remix-run/router error";
@@ -3500,6 +3577,8 @@ function getInternalRouterError(status, _temp4) {
3500
3577
 
3501
3578
  if (method && pathname && routeId) {
3502
3579
  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.";
3580
+ } else if (type === "defer-action") {
3581
+ errorMessage = "defer() is not supported in actions";
3503
3582
  } else {
3504
3583
  errorMessage = "Cannot submit binary form data using GET";
3505
3584
  }
@@ -3669,5 +3748,5 @@ function getTargetMatch(matches, location) {
3669
3748
  return pathMatches[pathMatches.length - 1];
3670
3749
  } //#endregion
3671
3750
 
3672
- export { AbortedDeferredError, Action, ErrorResponse, IDLE_FETCHER, IDLE_NAVIGATION, convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes, getPathContributingMatches as UNSAFE_getPathContributingMatches, createBrowserHistory, createHashHistory, createMemoryHistory, createPath, createRouter, createStaticHandler, defer, generatePath, getStaticContextFromError, getToPathname, invariant, isRouteErrorResponse, joinPaths, json, matchPath, matchRoutes, normalizePathname, parsePath, redirect, resolvePath, resolveTo, stripBasename, warning };
3751
+ export { AbortedDeferredError, Action, ErrorResponse, IDLE_FETCHER, IDLE_NAVIGATION, UNSAFE_DEFERRED_SYMBOL, DeferredData as UNSAFE_DeferredData, convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes, getPathContributingMatches as UNSAFE_getPathContributingMatches, createBrowserHistory, createHashHistory, createMemoryHistory, createPath, createRouter, createStaticHandler, defer, generatePath, getStaticContextFromError, getToPathname, invariant, isRouteErrorResponse, joinPaths, json, matchPath, matchRoutes, normalizePathname, parsePath, redirect, resolvePath, resolveTo, stripBasename, warning };
3673
3752
  //# sourceMappingURL=router.js.map