@remix-run/router 1.2.1 → 1.3.0-pre.1

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
  /**
@@ -284,6 +285,7 @@ declare type LinkNavigateOptions = {
284
285
  declare type SubmissionNavigateOptions = {
285
286
  replace?: boolean;
286
287
  state?: any;
288
+ preventScrollReset?: boolean;
287
289
  formMethod?: FormMethod;
288
290
  formEncType?: FormEncType;
289
291
  formData: FormData;
@@ -366,6 +368,7 @@ export declare const IDLE_FETCHER: FetcherStates["Idle"];
366
368
  * Create a router and listen to history POP navigations
367
369
  */
368
370
  export declare function createRouter(init: RouterInit): Router;
371
+ export declare const UNSAFE_DEFERRED_SYMBOL: unique symbol;
369
372
  export declare function createStaticHandler(routes: AgnosticRouteObject[], opts?: {
370
373
  basename?: string;
371
374
  }): 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.1
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".
@@ -1498,7 +1542,7 @@ function createRouter(init) {
1498
1542
 
1499
1543
 
1500
1544
  function completeNavigation(location, newState) {
1501
- var _location$state;
1545
+ var _location$state, _location$state2;
1502
1546
 
1503
1547
  // Deduce if we're in a loading/actionReload state:
1504
1548
  // - We have committed actionData in the store
@@ -1524,7 +1568,10 @@ function createRouter(init) {
1524
1568
  } // Always preserve any existing loaderData from re-used routes
1525
1569
 
1526
1570
 
1527
- let loaderData = newState.loaderData ? mergeLoaderData(state.loaderData, newState.loaderData, newState.matches || [], newState.errors) : state.loaderData;
1571
+ let loaderData = newState.loaderData ? mergeLoaderData(state.loaderData, newState.loaderData, newState.matches || [], newState.errors) : state.loaderData; // Always respect the user flag. Otherwise don't reset on mutation
1572
+ // submission navigations unless they redirect
1573
+
1574
+ let preventScrollReset = pendingPreventScrollReset === true || state.navigation.formMethod != null && isMutationMethod(state.navigation.formMethod) && ((_location$state2 = location.state) == null ? void 0 : _location$state2._isRedirect) !== true;
1528
1575
  updateState(_extends({}, newState, {
1529
1576
  actionData,
1530
1577
  loaderData,
@@ -1533,9 +1580,8 @@ function createRouter(init) {
1533
1580
  initialized: true,
1534
1581
  navigation: IDLE_NAVIGATION,
1535
1582
  revalidation: "idle",
1536
- // Don't restore on submission navigations
1537
- restoreScrollPosition: state.navigation.formData ? false : getSavedScrollPosition(location, newState.matches || state.matches),
1538
- preventScrollReset: pendingPreventScrollReset
1583
+ restoreScrollPosition: getSavedScrollPosition(location, newState.matches || state.matches),
1584
+ preventScrollReset
1539
1585
  }));
1540
1586
 
1541
1587
  if (isUninterruptedRevalidation) ; else if (pendingAction === Action.Pop) ; else if (pendingAction === Action.Push) {
@@ -1677,7 +1723,7 @@ function createRouter(init) {
1677
1723
 
1678
1724
 
1679
1725
  pendingNavigationController = new AbortController();
1680
- let request = createClientSideRequest(location, pendingNavigationController.signal, opts && opts.submission);
1726
+ let request = createClientSideRequest(init.history, location, pendingNavigationController.signal, opts && opts.submission);
1681
1727
  let pendingActionData;
1682
1728
  let pendingError;
1683
1729
 
@@ -1818,7 +1864,9 @@ function createRouter(init) {
1818
1864
  }
1819
1865
 
1820
1866
  if (isDeferredResult(result)) {
1821
- throw new Error("defer() is not supported in actions");
1867
+ throw getInternalRouterError(400, {
1868
+ type: "defer-action"
1869
+ });
1822
1870
  }
1823
1871
 
1824
1872
  return {
@@ -1855,7 +1903,7 @@ function createRouter(init) {
1855
1903
  formData: loadingNavigation.formData,
1856
1904
  formEncType: loadingNavigation.formEncType
1857
1905
  } : 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
1906
+ 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
1907
  // about to reload. Note that if this is an action reload we would have
1860
1908
  // already cancelled all pending deferreds so this would be a no-op
1861
1909
 
@@ -2037,7 +2085,7 @@ function createRouter(init) {
2037
2085
  }); // Call the action for the fetcher
2038
2086
 
2039
2087
  let abortController = new AbortController();
2040
- let fetchRequest = createClientSideRequest(path, abortController.signal, submission);
2088
+ let fetchRequest = createClientSideRequest(init.history, path, abortController.signal, submission);
2041
2089
  fetchControllers.set(key, abortController);
2042
2090
  let actionResult = await callLoaderOrAction("action", fetchRequest, match, requestMatches, router.basename);
2043
2091
 
@@ -2078,13 +2126,15 @@ function createRouter(init) {
2078
2126
  }
2079
2127
 
2080
2128
  if (isDeferredResult(actionResult)) {
2081
- invariant(false, "defer() is not supported in actions");
2129
+ throw getInternalRouterError(400, {
2130
+ type: "defer-action"
2131
+ });
2082
2132
  } // Start the data load for current matches, or the next location if we're
2083
2133
  // in the middle of a navigation
2084
2134
 
2085
2135
 
2086
2136
  let nextLocation = state.navigation.location || state.location;
2087
- let revalidationRequest = createClientSideRequest(nextLocation, abortController.signal);
2137
+ let revalidationRequest = createClientSideRequest(init.history, nextLocation, abortController.signal);
2088
2138
  let matches = state.navigation.state !== "idle" ? matchRoutes(dataRoutes, state.navigation.location, init.basename) : state.matches;
2089
2139
  invariant(matches, "Didn't find any matches after fetcher action");
2090
2140
  let loadId = ++incrementingLoadId;
@@ -2098,7 +2148,7 @@ function createRouter(init) {
2098
2148
  });
2099
2149
 
2100
2150
  state.fetchers.set(key, loadFetcher);
2101
- let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, {
2151
+ let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, {
2102
2152
  [match.route.id]: actionResult.data
2103
2153
  }, undefined, // No need to send through errors since we short circuit above
2104
2154
  fetchLoadMatches); // Put all revalidating fetchers into the loading state, except for the
@@ -2211,9 +2261,9 @@ function createRouter(init) {
2211
2261
  }); // Call the loader for this fetcher route match
2212
2262
 
2213
2263
  let abortController = new AbortController();
2214
- let fetchRequest = createClientSideRequest(path, abortController.signal);
2264
+ let fetchRequest = createClientSideRequest(init.history, path, abortController.signal);
2215
2265
  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
2266
+ let result = await callLoaderOrAction("loader", fetchRequest, match, matches, router.basename); // Deferred isn't supported for fetcher loads, await everything and treat it
2217
2267
  // as a normal load. resolveDeferredData will return undefined if this
2218
2268
  // fetcher gets aborted, so we just leave result untouched and short circuit
2219
2269
  // below if that happens
@@ -2313,7 +2363,7 @@ function createRouter(init) {
2313
2363
  invariant(redirectLocation, "Expected a location on the redirect navigation"); // Check if this an external redirect that goes to a new origin
2314
2364
 
2315
2365
  if (typeof ((_window = window) == null ? void 0 : _window.location) !== "undefined") {
2316
- let newOrigin = createClientSideURL(redirect.location).origin;
2366
+ let newOrigin = init.history.createURL(redirect.location).origin;
2317
2367
 
2318
2368
  if (window.location.origin !== newOrigin) {
2319
2369
  if (replace) {
@@ -2355,7 +2405,9 @@ function createRouter(init) {
2355
2405
  await startNavigation(redirectHistoryAction, redirectLocation, {
2356
2406
  submission: _extends({}, submission, {
2357
2407
  formAction: redirect.location
2358
- })
2408
+ }),
2409
+ // Preserve this flag across redirects
2410
+ preventScrollReset: pendingPreventScrollReset
2359
2411
  });
2360
2412
  } else {
2361
2413
  // Otherwise, we kick off a new loading navigation, preserving the
@@ -2368,7 +2420,9 @@ function createRouter(init) {
2368
2420
  formAction: submission ? submission.formAction : undefined,
2369
2421
  formEncType: submission ? submission.formEncType : undefined,
2370
2422
  formData: submission ? submission.formData : undefined
2371
- }
2423
+ },
2424
+ // Preserve this flag across redirects
2425
+ preventScrollReset: pendingPreventScrollReset
2372
2426
  });
2373
2427
  }
2374
2428
  }
@@ -2379,7 +2433,7 @@ function createRouter(init) {
2379
2433
  // accordingly
2380
2434
  let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, router.basename)), ...fetchersToLoad.map(_ref8 => {
2381
2435
  let [, href, match, fetchMatches] = _ref8;
2382
- return callLoaderOrAction("loader", createClientSideRequest(href, request.signal), match, fetchMatches, router.basename);
2436
+ return callLoaderOrAction("loader", createClientSideRequest(init.history, href, request.signal), match, fetchMatches, router.basename);
2383
2437
  })]);
2384
2438
  let loaderResults = results.slice(0, matchesToLoad.length);
2385
2439
  let fetcherResults = results.slice(matchesToLoad.length);
@@ -2588,6 +2642,7 @@ function createRouter(init) {
2588
2642
  //#region createStaticHandler
2589
2643
  ////////////////////////////////////////////////////////////////////////////////
2590
2644
 
2645
+ const UNSAFE_DEFERRED_SYMBOL = Symbol("deferred");
2591
2646
  function createStaticHandler(routes, opts) {
2592
2647
  invariant(routes.length > 0, "You must provide a non-empty routes array to createStaticHandler");
2593
2648
  let dataRoutes = convertRoutesToDataRoutes(routes);
@@ -2640,7 +2695,8 @@ function createStaticHandler(routes, opts) {
2640
2695
  },
2641
2696
  statusCode: error.status,
2642
2697
  loaderHeaders: {},
2643
- actionHeaders: {}
2698
+ actionHeaders: {},
2699
+ activeDeferreds: null
2644
2700
  };
2645
2701
  } else if (!matches) {
2646
2702
  let error = getInternalRouterError(404, {
@@ -2661,7 +2717,8 @@ function createStaticHandler(routes, opts) {
2661
2717
  },
2662
2718
  statusCode: error.status,
2663
2719
  loaderHeaders: {},
2664
- actionHeaders: {}
2720
+ actionHeaders: {},
2721
+ activeDeferreds: null
2665
2722
  };
2666
2723
  }
2667
2724
 
@@ -2752,8 +2809,23 @@ function createStaticHandler(routes, opts) {
2752
2809
  } // Pick off the right state value to return
2753
2810
 
2754
2811
 
2755
- let routeData = [result.actionData, result.loaderData].find(v => v);
2756
- return Object.values(routeData || {})[0];
2812
+ if (result.actionData) {
2813
+ return Object.values(result.actionData)[0];
2814
+ }
2815
+
2816
+ if (result.loaderData) {
2817
+ var _result$activeDeferre;
2818
+
2819
+ let data = Object.values(result.loaderData)[0];
2820
+
2821
+ if ((_result$activeDeferre = result.activeDeferreds) != null && _result$activeDeferre[match.route.id]) {
2822
+ data[UNSAFE_DEFERRED_SYMBOL] = result.activeDeferreds[match.route.id];
2823
+ }
2824
+
2825
+ return data;
2826
+ }
2827
+
2828
+ return undefined;
2757
2829
  }
2758
2830
 
2759
2831
  async function queryImpl(request, location, matches, requestContext, routeMatch) {
@@ -2833,7 +2905,18 @@ function createStaticHandler(routes, opts) {
2833
2905
  }
2834
2906
 
2835
2907
  if (isDeferredResult(result)) {
2836
- throw new Error("defer() is not supported in actions");
2908
+ let error = getInternalRouterError(400, {
2909
+ type: "defer-action"
2910
+ });
2911
+
2912
+ if (isRouteRequest) {
2913
+ throw error;
2914
+ }
2915
+
2916
+ result = {
2917
+ type: ResultType.error,
2918
+ error
2919
+ };
2837
2920
  }
2838
2921
 
2839
2922
  if (isRouteRequest) {
@@ -2854,7 +2937,8 @@ function createStaticHandler(routes, opts) {
2854
2937
  // return the raw Response or value
2855
2938
  statusCode: 200,
2856
2939
  loaderHeaders: {},
2857
- actionHeaders: {}
2940
+ actionHeaders: {},
2941
+ activeDeferreds: null
2858
2942
  };
2859
2943
  }
2860
2944
 
@@ -2917,7 +3001,8 @@ function createStaticHandler(routes, opts) {
2917
3001
  }), {}),
2918
3002
  errors: pendingActionError || null,
2919
3003
  statusCode: 200,
2920
- loaderHeaders: {}
3004
+ loaderHeaders: {},
3005
+ activeDeferreds: null
2921
3006
  };
2922
3007
  }
2923
3008
 
@@ -2926,27 +3011,21 @@ function createStaticHandler(routes, opts) {
2926
3011
  if (request.signal.aborted) {
2927
3012
  let method = isRouteRequest ? "queryRoute" : "query";
2928
3013
  throw new Error(method + "() call aborted");
2929
- }
2930
-
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
3014
+ } // Process and commit output from loaders
2935
3015
 
2936
- if (isDeferredResult(result)) {
2937
- result.deferredData.cancel();
2938
- }
2939
- }); // Process and commit output from loaders
2940
3016
 
2941
- let context = processRouteLoaderData(matches, matchesToLoad, results, pendingActionError); // Add a null for any non-loader matches for proper revalidation on the client
3017
+ let activeDeferreds = new Map();
3018
+ let context = processRouteLoaderData(matches, matchesToLoad, results, pendingActionError, activeDeferreds); // Add a null for any non-loader matches for proper revalidation on the client
2942
3019
 
3020
+ let executedLoaders = new Set(matchesToLoad.map(match => match.route.id));
2943
3021
  matches.forEach(match => {
2944
3022
  if (!executedLoaders.has(match.route.id)) {
2945
3023
  context.loaderData[match.route.id] = null;
2946
3024
  }
2947
3025
  });
2948
3026
  return _extends({}, context, {
2949
- matches
3027
+ matches,
3028
+ activeDeferreds: activeDeferreds.size > 0 ? Object.fromEntries(activeDeferreds.entries()) : null
2950
3029
  });
2951
3030
  }
2952
3031
 
@@ -3065,13 +3144,13 @@ function getLoaderMatchesUntilBoundary(matches, boundaryId) {
3065
3144
  return boundaryMatches;
3066
3145
  }
3067
3146
 
3068
- function getMatchesToLoad(state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, pendingActionData, pendingError, fetchLoadMatches) {
3147
+ function getMatchesToLoad(history, state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, pendingActionData, pendingError, fetchLoadMatches) {
3069
3148
  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
3149
 
3071
3150
  let boundaryId = pendingError ? Object.keys(pendingError)[0] : undefined;
3072
3151
  let boundaryMatches = getLoaderMatchesUntilBoundary(matches, boundaryId);
3073
3152
  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
3153
+ 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
3154
 
3076
3155
  let revalidatingFetchers = [];
3077
3156
  fetchLoadMatches && fetchLoadMatches.forEach((_ref10, key) => {
@@ -3081,7 +3160,7 @@ function getMatchesToLoad(state, matches, submission, location, isRevalidationRe
3081
3160
  if (cancelledFetcherLoads.includes(key)) {
3082
3161
  revalidatingFetchers.push([key, href, match, fetchMatches]);
3083
3162
  } else if (isRevalidationRequired) {
3084
- let shouldRevalidate = shouldRevalidateLoader(href, match, submission, href, match, isRevalidationRequired, actionResult);
3163
+ let shouldRevalidate = shouldRevalidateLoader(history, href, match, submission, href, match, isRevalidationRequired, actionResult);
3085
3164
 
3086
3165
  if (shouldRevalidate) {
3087
3166
  revalidatingFetchers.push([key, href, match, fetchMatches]);
@@ -3111,10 +3190,10 @@ function isNewRouteInstance(currentMatch, match) {
3111
3190
  );
3112
3191
  }
3113
3192
 
3114
- function shouldRevalidateLoader(currentLocation, currentMatch, submission, location, match, isRevalidationRequired, actionResult) {
3115
- let currentUrl = createClientSideURL(currentLocation);
3193
+ function shouldRevalidateLoader(history, currentLocation, currentMatch, submission, location, match, isRevalidationRequired, actionResult) {
3194
+ let currentUrl = history.createURL(currentLocation);
3116
3195
  let currentParams = currentMatch.params;
3117
- let nextUrl = createClientSideURL(location);
3196
+ let nextUrl = history.createURL(location);
3118
3197
  let nextParams = match.params; // This is the default implementation as to when we revalidate. If the route
3119
3198
  // provides it's own implementation, then we give them full control but
3120
3199
  // provide this value so they can leverage it if needed after they check
@@ -3191,7 +3270,7 @@ async function callLoaderOrAction(type, request, match, matches, basename, isSta
3191
3270
  if (redirectStatusCodes.has(status)) {
3192
3271
  let location = result.headers.get("Location");
3193
3272
  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
3273
+ let isAbsolute = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(location); // Support relative routing in internal redirects
3195
3274
 
3196
3275
  if (!isAbsolute) {
3197
3276
  let activeMatches = matches.slice(0, matches.indexOf(match) + 1);
@@ -3284,8 +3363,8 @@ async function callLoaderOrAction(type, request, match, matches, basename, isSta
3284
3363
  // Request instance from the static handler (query/queryRoute)
3285
3364
 
3286
3365
 
3287
- function createClientSideRequest(location, signal, submission) {
3288
- let url = createClientSideURL(stripHashFromPath(location)).toString();
3366
+ function createClientSideRequest(history, location, signal, submission) {
3367
+ let url = history.createURL(stripHashFromPath(location)).toString();
3289
3368
  let init = {
3290
3369
  signal
3291
3370
  };
@@ -3358,13 +3437,16 @@ function processRouteLoaderData(matches, matchesToLoad, results, pendingError, a
3358
3437
  if (result.headers) {
3359
3438
  loaderHeaders[id] = result.headers;
3360
3439
  }
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
3440
  } else {
3365
- loaderData[id] = result.data; // Error status codes always override success status codes, but if all
3441
+ if (isDeferredResult(result)) {
3442
+ activeDeferreds.set(id, result.deferredData);
3443
+ loaderData[id] = result.deferredData.data;
3444
+ } else {
3445
+ loaderData[id] = result.data;
3446
+ } // Error status codes always override success status codes, but if all
3366
3447
  // loaders are successful we take the deepest status code.
3367
3448
 
3449
+
3368
3450
  if (result.statusCode != null && result.statusCode !== 200 && !foundError) {
3369
3451
  statusCode = result.statusCode;
3370
3452
  }
@@ -3414,11 +3496,11 @@ function processLoaderData(state, matches, matchesToLoad, results, pendingError,
3414
3496
  } else if (isRedirectResult(result)) {
3415
3497
  // Should never get here, redirects should get processed above, but we
3416
3498
  // keep this to type narrow to a success result in the else
3417
- throw new Error("Unhandled fetcher revalidation redirect");
3499
+ invariant(false, "Unhandled fetcher revalidation redirect");
3418
3500
  } else if (isDeferredResult(result)) {
3419
3501
  // Should never get here, deferred data should be awaited for fetchers
3420
3502
  // in resolveDeferredResults
3421
- throw new Error("Unhandled fetcher deferred data");
3503
+ invariant(false, "Unhandled fetcher deferred data");
3422
3504
  } else {
3423
3505
  let doneFetcher = {
3424
3506
  state: "idle",
@@ -3490,7 +3572,8 @@ function getInternalRouterError(status, _temp4) {
3490
3572
  let {
3491
3573
  pathname,
3492
3574
  routeId,
3493
- method
3575
+ method,
3576
+ type
3494
3577
  } = _temp4 === void 0 ? {} : _temp4;
3495
3578
  let statusText = "Unknown Server Error";
3496
3579
  let errorMessage = "Unknown @remix-run/router error";
@@ -3500,6 +3583,8 @@ function getInternalRouterError(status, _temp4) {
3500
3583
 
3501
3584
  if (method && pathname && routeId) {
3502
3585
  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.";
3586
+ } else if (type === "defer-action") {
3587
+ errorMessage = "defer() is not supported in actions";
3503
3588
  } else {
3504
3589
  errorMessage = "Cannot submit binary form data using GET";
3505
3590
  }
@@ -3669,5 +3754,5 @@ function getTargetMatch(matches, location) {
3669
3754
  return pathMatches[pathMatches.length - 1];
3670
3755
  } //#endregion
3671
3756
 
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 };
3757
+ 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
3758
  //# sourceMappingURL=router.js.map