crelte 0.1.3 → 0.2.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.
Files changed (53) hide show
  1. package/dist/CrelteRequest.d.ts +11 -6
  2. package/dist/CrelteRequest.d.ts.map +1 -1
  3. package/dist/CrelteRequest.js +14 -14
  4. package/dist/graphql/GraphQl.d.ts +1 -1
  5. package/dist/graphql/GraphQl.d.ts.map +1 -1
  6. package/dist/graphql/GraphQl.js +1 -1
  7. package/dist/index.d.ts +3 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +10 -3
  10. package/dist/init/client.d.ts.map +1 -1
  11. package/dist/init/client.js +11 -5
  12. package/dist/init/server.d.ts +2 -0
  13. package/dist/init/server.d.ts.map +1 -1
  14. package/dist/init/server.js +24 -10
  15. package/dist/init/shared.d.ts +3 -3
  16. package/dist/init/shared.d.ts.map +1 -1
  17. package/dist/init/shared.js +1 -1
  18. package/dist/loadData/index.d.ts +11 -5
  19. package/dist/loadData/index.d.ts.map +1 -1
  20. package/dist/loadData/index.js +15 -6
  21. package/dist/routing/History.d.ts +5 -3
  22. package/dist/routing/History.d.ts.map +1 -1
  23. package/dist/routing/History.js +9 -4
  24. package/dist/routing/InnerRouter.d.ts +31 -21
  25. package/dist/routing/InnerRouter.d.ts.map +1 -1
  26. package/dist/routing/InnerRouter.js +98 -76
  27. package/dist/routing/PageLoader.d.ts +4 -5
  28. package/dist/routing/PageLoader.d.ts.map +1 -1
  29. package/dist/routing/PageLoader.js +5 -5
  30. package/dist/routing/Request.d.ts +15 -2
  31. package/dist/routing/Request.d.ts.map +1 -1
  32. package/dist/routing/Request.js +22 -1
  33. package/dist/routing/Route.d.ts +61 -25
  34. package/dist/routing/Route.d.ts.map +1 -1
  35. package/dist/routing/Route.js +90 -41
  36. package/dist/routing/Router.d.ts +34 -13
  37. package/dist/routing/Router.d.ts.map +1 -1
  38. package/dist/routing/Router.js +102 -49
  39. package/package.json +3 -2
  40. package/src/CrelteRequest.ts +14 -19
  41. package/src/graphql/GraphQl.ts +5 -2
  42. package/src/index.ts +26 -3
  43. package/src/init/client.ts +14 -10
  44. package/src/init/server.ts +31 -11
  45. package/src/init/shared.ts +4 -4
  46. package/src/loadData/index.ts +47 -15
  47. package/src/routing/History.ts +12 -5
  48. package/src/routing/InnerRouter.ts +109 -82
  49. package/src/routing/PageLoader.ts +7 -17
  50. package/src/routing/Request.ts +28 -6
  51. package/src/routing/Route.ts +115 -52
  52. package/src/routing/Router.ts +123 -59
  53. package/LICENSE.md +0 -41
@@ -5,6 +5,20 @@ import type { Global } from './Globals.js';
5
5
 
6
6
  export type { Globals, Global };
7
7
 
8
+ export interface LoadDataFn<A1 = any> {
9
+ (cr: CrelteRequest, entryOrBlock: A1, ...args: any[]): Promise<any> | any;
10
+ }
11
+
12
+ export interface LoadDataObj<A1 = any> {
13
+ [key: string]: LoadData<A1>;
14
+ }
15
+
16
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
17
+ export interface LoadDataArray<A1 = any> extends Array<LoadData<A1>> {}
18
+
19
+ // todo link to the real docs maybe instead of showing an example
20
+ // so we can add @type {import('crelte').LoadData}
21
+ // maybe enabling markdown might be enough: https://jsdoc.app/plugins-markdown
8
22
  /**
9
23
  * Load data function
10
24
  *
@@ -15,8 +29,6 @@ export type { Globals, Global };
15
29
  * Each property should be a loadData type, each one is called in parallel.
16
30
  * And will be available to your component with the same name.
17
31
  * ```
18
- * export const loadData = {
19
- *
20
32
  * import entriesQuery from '@/queries/entries.graphql';
21
33
  * import { loadData as headerLoadData } from '@/layout/header.svelte';
22
34
  *
@@ -71,20 +83,30 @@ export type { Globals, Global };
71
83
  * }
72
84
  * ```
73
85
  */
74
-
75
- export type LoadData<T> =
76
- | ((cr: CrelteRequest, ...args: any[]) => Promise<T>)
86
+ export type LoadData<A1 = any> =
87
+ | LoadDataFn<A1>
77
88
  | GraphQlQuery
78
- | T;
89
+ | LoadDataObj<A1>
90
+ | LoadDataArray<A1>
91
+ | string
92
+ | number
93
+ | null
94
+ | undefined;
95
+
96
+ // export type LoadData<A1 = any, R = any> =
97
+ // | ((cr: CrelteRequest, entryOrBlock: A1, ...args: any[]) => Promise<R>)
98
+ // | GraphQlQuery
99
+ // | Record<string, LoadData<A1, R>>;
79
100
 
80
- export async function callLoadData(
81
- ld: LoadData<unknown>,
101
+ export async function callLoadData<A1 = any>(
102
+ ld: LoadData<A1>,
82
103
  cr: CrelteRequest,
104
+ arg1: A1,
83
105
  ...args: any[]
84
- ): Promise<unknown> {
106
+ ): Promise<any> {
85
107
  // either we have a function
86
108
  if (typeof ld === 'function') {
87
- return await ld(cr, ...args);
109
+ return await ld(cr, arg1, ...args);
88
110
  }
89
111
 
90
112
  // or a graphql query
@@ -92,10 +114,16 @@ export async function callLoadData(
92
114
  return await cr.query(ld);
93
115
  }
94
116
 
117
+ if (ld === null || typeof ld === 'undefined') return null;
118
+
119
+ if (Array.isArray(ld)) {
120
+ return await mergeLoadData(...ld)(cr, arg1, ...args);
121
+ }
122
+
95
123
  // or an object
96
- if (typeof ld === 'object' && ld !== null) {
124
+ if (typeof ld === 'object') {
97
125
  const data = await Promise.all(
98
- Object.values(ld).map(nld => callLoadData(nld, cr, ...args)),
126
+ Object.values(ld).map(nld => callLoadData(nld, cr, arg1, ...args)),
99
127
  );
100
128
 
101
129
  return Object.fromEntries(
@@ -119,10 +147,14 @@ export async function callLoadData(
119
147
  * );
120
148
  * ```
121
149
  */
122
- export function mergeLoadData(...lds: LoadData<object>[]): LoadData<object> {
123
- return async (cr: CrelteRequest, ...args: any[]) => {
150
+ export function mergeLoadData<A1 = any>(
151
+ ...lds: LoadData<A1>[]
152
+ ): LoadDataFn<A1> {
153
+ return async (cr: CrelteRequest, arg1, ...args: any[]) => {
124
154
  const datas = await Promise.all(
125
- lds.map(ld => callLoadData(ld, cr, ...args) as Promise<object>),
155
+ lds.map(
156
+ ld => callLoadData(ld, cr, arg1, ...args) as Promise<object>,
157
+ ),
126
158
  );
127
159
 
128
160
  return datas.reduce((acc, data) => ({ ...acc, ...data }), {});
@@ -1,8 +1,10 @@
1
+ import Request from './Request.js';
2
+
1
3
  export default interface History {
2
4
  scrollY(): number | null;
3
5
  replaceState(data: any, url?: string): void;
4
6
  pushState(data: any, url: string): void;
5
- open(url: string): void;
7
+ open(req: Request): void;
6
8
  back(): void;
7
9
  }
8
10
 
@@ -19,8 +21,8 @@ export class ClientHistory implements History {
19
21
  history.pushState(data, '', url);
20
22
  }
21
23
 
22
- open(url: string): void {
23
- window.location.href = url;
24
+ open(req: Request): void {
25
+ window.location.href = req.url.href;
24
26
  }
25
27
 
26
28
  back(): void {
@@ -31,10 +33,12 @@ export class ClientHistory implements History {
31
33
  export class ServerHistory implements History {
32
34
  state: any | null;
33
35
  url: string | null;
36
+ req: Request | null;
34
37
 
35
38
  constructor() {
36
39
  this.state = null;
37
40
  this.url = null;
41
+ this.req = null;
38
42
  }
39
43
 
40
44
  scrollY(): number | null {
@@ -44,15 +48,18 @@ export class ServerHistory implements History {
44
48
  replaceState(data: any, url?: string): void {
45
49
  this.state = data;
46
50
  this.url = url ?? null;
51
+ this.req = null;
47
52
  }
48
53
 
49
54
  pushState(data: any, url: string): void {
50
55
  this.state = data;
51
56
  this.url = url;
57
+ this.req = null;
52
58
  }
53
59
 
54
- open(url: string): void {
55
- this.url = url;
60
+ open(req: Request): void {
61
+ this.req = req;
62
+ this.url = null;
56
63
  }
57
64
 
58
65
  back(): void {
@@ -1,7 +1,7 @@
1
1
  import Site, { SiteFromGraphQl } from './Site.js';
2
2
  import History from './History.js';
3
3
  import { ClientHistory, ServerHistory } from './History.js';
4
- import Request, { isRequest } from './Request.js';
4
+ import Request, { isRequest, RequestOptions } from './Request.js';
5
5
  import Route from './Route.js';
6
6
 
7
7
  export type InnerRouterOpts = {
@@ -13,16 +13,21 @@ export type InnerRouterOpts = {
13
13
  */
14
14
  export default class InnerRouter {
15
15
  sites: Site[];
16
+ /**
17
+ * The current route
18
+ *
19
+ * ## Null
20
+ * It might be null on the first targetToRequest, open, and routeFromUrl call
21
+ */
16
22
  route: Route | null;
17
- site: Site;
18
23
  history: History;
19
24
  preloadOnMouseOver: boolean;
20
25
  /**
21
26
  * @param changeHistory returns a function you need to call when you are ready to
22
27
  update the window history (note do not call this after another onRoute call was made)
23
28
  */
24
- onRoute: (route: Request, site: Site, changeHistory: () => void) => void;
25
- onPreload: (route: Request, site: Site) => void;
29
+ onRoute: (route: Request, changeHistory: () => void) => void;
30
+ onPreload: (route: Request) => void;
26
31
 
27
32
  private scrollDebounceTimeout: any | null;
28
33
 
@@ -36,7 +41,6 @@ export default class InnerRouter {
36
41
  this.sites = sites.map(s => new Site(s));
37
42
 
38
43
  this.route = null;
39
- this.site = this.defaultSite();
40
44
  // @ts-ignore
41
45
  this.history = import.meta.env.SSR
42
46
  ? new ServerHistory()
@@ -58,18 +62,13 @@ export default class InnerRouter {
58
62
  this.listen();
59
63
 
60
64
  // let's first try to load from the state
61
- const route = this.targetToRequest(window.location.href);
62
- route._fillFromState(window.history.state);
63
-
64
- route.origin = 'init';
65
-
66
- if (route.search.get('x-craft-live-preview')) {
67
- route.origin = 'live-preview-init';
68
- }
65
+ const req = this.targetToRequest(window.location.href);
66
+ req._fillFromState(window.history.state);
69
67
 
68
+ req.origin = 'init';
70
69
  window.history.scrollRestoration = 'manual';
71
70
 
72
- this.open(route, false);
71
+ this.setRoute(req);
73
72
  }
74
73
 
75
74
  /**
@@ -80,8 +79,7 @@ export default class InnerRouter {
80
79
  /**
81
80
  * Get a site and if possible use the accept lang header.
82
81
  *
83
- * @param {(string|null)} [acceptLang=null] Accept Language header.
84
- * @return {Site}
82
+ * @param acceptLang Accept Language header.
85
83
  */
86
84
  siteByAcceptLang(acceptLang: string | null = null): Site {
87
85
  if (!acceptLang) return this.defaultSite();
@@ -125,7 +123,7 @@ export default class InnerRouter {
125
123
  * Get the default site
126
124
  */
127
125
  defaultSite(): Site {
128
- return this.sites[0];
126
+ return this.sites.find(s => s.primary) ?? this.sites[0];
129
127
  }
130
128
 
131
129
  /**
@@ -136,15 +134,21 @@ export default class InnerRouter {
136
134
  }
137
135
 
138
136
  /**
139
- * Resolve a url or Route and convert it to a Route
137
+ * Resolve a url or Route and convert it to a Request
140
138
  *
141
139
  * @param target
140
+ * @param opts, any option present will override the value in target
142
141
  * @return Returns null if the url does not match our host (the protocol get's ignored)
143
142
  */
144
- targetToRequest(target: string | URL | Route | Request): Request {
143
+ targetToRequest(
144
+ target: string | URL | Route | Request,
145
+ opts: RequestOptions = {},
146
+ ): Request {
145
147
  if (typeof target === 'string') {
146
148
  if (target.startsWith('/')) {
147
- const site = this.site;
149
+ // todo should we use the language matching or throw if the route does not
150
+ // exists
151
+ const site = this.route?.site ?? this.defaultSite();
148
152
  target = new URL(site.uri + target, site.url);
149
153
  } else {
150
154
  target = new URL(target);
@@ -156,9 +160,10 @@ export default class InnerRouter {
156
160
  }
157
161
 
158
162
  if (!isRequest(target)) {
159
- return Request.fromRoute(target);
163
+ return Request.fromRoute(target, opts);
160
164
  }
161
165
 
166
+ target._updateOpts(opts);
162
167
  return target;
163
168
  }
164
169
 
@@ -170,7 +175,7 @@ export default class InnerRouter {
170
175
  */
171
176
  routeFromUrl(fullUrl: URL): Route {
172
177
  // strip stuff we dont need from url
173
- const route = new Route(fullUrl, null);
178
+ const route = new Route(fullUrl, null!);
174
179
  const url = route.url;
175
180
 
176
181
  let site: Site | null = null;
@@ -193,7 +198,9 @@ export default class InnerRouter {
193
198
  site = s;
194
199
  }
195
200
 
196
- route.site = site;
201
+ // todo should we throw if we can't find a site
202
+ // or use the site which matches the language
203
+ route.site = site ?? this.defaultSite();
197
204
 
198
205
  return route;
199
206
  }
@@ -210,12 +217,20 @@ export default class InnerRouter {
210
217
 
211
218
  e.preventDefault();
212
219
 
213
- const route = this.routeFromUrl(link.href);
214
- if (this.route?.eq(route)) return;
215
-
216
- route.origin = 'click';
220
+ const req = this.targetToRequest(link.href, { origin: 'click' });
221
+ const routeEq =
222
+ this.route && this.route.eqUrl(req) && this.route.eqSearch(req);
223
+ // the route is the same don't do anything
224
+ // or maybe scroll the page to the hash? todo
225
+ if (routeEq && this.route?.eqHash(req)) return;
226
+
227
+ // this means the hash did not match, so we wan't to just scroll but not load
228
+ // data
229
+ if (routeEq) {
230
+ req.disableLoadData = true;
231
+ }
217
232
 
218
- this.open(route);
233
+ this.open(req);
219
234
  });
220
235
 
221
236
  if (this.preloadOnMouseOver) {
@@ -259,7 +274,7 @@ export default class InnerRouter {
259
274
  // use the latest state
260
275
  this.history.replaceState(this.route._toState());
261
276
 
262
- if (current.origin === 'live-preview-init') {
277
+ if (current.inLivePreview()) {
263
278
  sessionStorage.setItem(
264
279
  'live-preview-scroll',
265
280
  // use the latest scrollY
@@ -275,27 +290,28 @@ export default class InnerRouter {
275
290
  window.addEventListener('popstate', async e => {
276
291
  if (!('route' in e.state)) return;
277
292
 
278
- const route = this.targetToRequest(window.location.href);
279
- route._fillFromState(e.state);
280
- route.origin = 'pop';
293
+ const req = this.targetToRequest(window.location.href);
294
+ req._fillFromState(e.state);
295
+ req.origin = 'pop';
281
296
 
282
- // since the pop event replaced our state we can't replace the state
283
- // for the scrollY in our open call so we just clear the current
284
- // route since it is now already the new route
285
- this.route = null;
286
-
287
- this.open(route, false);
297
+ this.setRoute(req);
288
298
  });
289
299
  }
290
300
 
291
301
  /**
292
- * Open's a route
302
+ * Open a new route
293
303
  *
294
304
  * @param route a route object or an url or uri, never input the same route object again
295
305
  * @param pushState if true pushed the state to the window.history
306
+ *
307
+ * ## Important
308
+ * Make sure a req always has the correct origin,
309
+ * `push` and `replace` will cause this function to throw an error
296
310
  */
297
- open(target: string | URL | Route | Request, pushState: boolean = true) {
298
- const req = this.targetToRequest(target);
311
+ open(req: Request) {
312
+ if (['push', 'replace'].includes(req.origin)) {
313
+ throw new Error('Do not use open with push or replace');
314
+ }
299
315
 
300
316
  const current = this.route;
301
317
  if (current) {
@@ -321,18 +337,14 @@ export default class InnerRouter {
321
337
  // @ts-ignore
322
338
  import.meta.env.SSR
323
339
  ) {
324
- this.history.open(req.url.href);
340
+ this.history.open(req);
325
341
  return;
326
342
  }
327
343
 
328
- if (pushState) {
329
- req.index = (current?.index ?? 0) + 1;
330
- this.onRoute(req, req.site ?? this.site, () => {
331
- this.pushState(req.toRoute());
332
- });
333
- } else {
334
- this.setRoute(req);
335
- }
344
+ req.index = (current?.index ?? 0) + 1;
345
+ this.onRoute(req, () => {
346
+ this.push(req, true);
347
+ });
336
348
  }
337
349
 
338
350
  /**
@@ -343,50 +355,70 @@ export default class InnerRouter {
343
355
  *
344
356
  * @param req
345
357
  */
346
- setRoute(req: Request) {
358
+ setRoute(req: Request, preventOnRoute = false) {
347
359
  this.route = req.toRoute();
348
- if (req.site) this.site = req.site;
349
360
 
350
- this.onRoute(req, this.site, () => {});
361
+ if (!preventOnRoute) this.onRoute(req, () => {});
351
362
  }
352
363
 
353
364
  /**
354
- * This pushes the state of the route without triggering a currentRoute
355
- * or currentSiteId change
365
+ * This pushes a new route to the history
356
366
  *
357
- * You can use when using pagination for example change the route object
358
- * (search argument) and then call pushState
367
+ * @param req, never input the same route object again
359
368
  *
360
- * @param route, never input the same route object again
369
+ * ## Important
370
+ * Make sure the route has the correct origin
361
371
  */
362
- pushState(route: Route) {
363
- const url = route.url;
372
+ push(req: Request, preventOnRoute = false) {
373
+ const url = req.url;
374
+ // todo a push should also store the previous scrollY
375
+
376
+ let nReq = req;
377
+ if (req.scrollY === null) {
378
+ // if there is no scrollY stored we store the current scrollY
379
+ // since a push does not cause a scroll top
380
+ // todo: probably should refactor something probably
381
+ // should not be here
382
+ nReq = req.clone();
383
+ nReq.scrollY = this.history.scrollY();
384
+ }
364
385
 
365
386
  this.history.pushState(
366
- route._toState(),
387
+ nReq._toState(),
367
388
  url.pathname + url.search + url.hash,
368
389
  );
369
390
 
370
- this.route = route;
371
- if (route.site) this.site = route.site;
391
+ this.setRoute(req, preventOnRoute);
372
392
  }
373
393
 
374
394
  /**
375
- * This replaces the state of the route without triggering a currentRoute
376
- * or currentSiteId change
395
+ * This replaces the current route
396
+ *
397
+ * @param req, never input the same route object again
377
398
  *
378
- * @param route, never input the same route object again
399
+ * ## Important
400
+ * Make sure the route has the correct origin
379
401
  */
380
- replaceState(route: Route) {
381
- const url = route.url;
402
+ replace(req: Request) {
403
+ const url = req.url;
404
+
405
+ let nReq = req;
406
+ if (req.scrollY === null) {
407
+ // if there is no scrollY stored we store the current scrollY
408
+ // since a replace does not cause a scrollTo and we wan't
409
+ // history back to work as intended
410
+ // todo: probably should refactor something probably
411
+ // should not be here
412
+ nReq = req.clone();
413
+ nReq.scrollY = this.history.scrollY();
414
+ }
382
415
 
383
416
  this.history.replaceState(
384
- route._toState(),
417
+ nReq._toState(),
385
418
  url.pathname + url.search + url.hash,
386
419
  );
387
420
 
388
- this.route = route;
389
- if (route.site) this.site = route.site;
421
+ this.setRoute(req);
390
422
  }
391
423
 
392
424
  /**
@@ -398,21 +430,12 @@ export default class InnerRouter {
398
430
  */
399
431
  preload(target: string | URL | Route | Request) {
400
432
  const req = this.targetToRequest(target);
401
-
402
- // todo, don't think this makes any sense
403
- // if the domain of the current site is different than the domain of the
404
- // new site id does not make sense to preload
405
- if (this.site.url.origin !== req.url.origin) {
406
- return;
407
- }
408
-
409
433
  const current = this.route;
410
- const site = req.site ?? this.site;
411
434
 
412
435
  // if the origin matches, the route will be able to be load
413
436
  // so let's preload it
414
437
  if (current && current.url.origin === req.url.origin) {
415
- this.onPreload(req, site);
438
+ this.onPreload(req);
416
439
  }
417
440
  }
418
441
 
@@ -427,7 +450,7 @@ export default class InnerRouter {
427
450
 
428
451
  // if the route is a live preview init and we have a scrollY stored
429
452
  // scroll to that
430
- if (req.origin === 'live-preview-init') {
453
+ if (req.inLivePreview()) {
431
454
  const scrollY = sessionStorage.getItem('live-preview-scroll');
432
455
  if (scrollY) {
433
456
  scrollTo = {
@@ -462,6 +485,10 @@ export default class InnerRouter {
462
485
  };
463
486
  }
464
487
 
488
+ // make sure push and replace don't cause a scroll if it is not intended
489
+ if (!scrollTo && (req.origin === 'push' || req.origin === 'replace'))
490
+ return;
491
+
465
492
  // scroll to the top if nothing else matches
466
493
  if (!scrollTo) {
467
494
  scrollTo = {
@@ -1,5 +1,4 @@
1
1
  import Request from './Request.js';
2
- import Site from './Site.js';
3
2
 
4
3
  export type PageLoaderOptions = {
5
4
  debugTiming: boolean;
@@ -10,11 +9,7 @@ export type LoadResponse = {
10
9
  data: any;
11
10
  };
12
11
 
13
- export type LoadFn = (
14
- req: Request,
15
- site: Site,
16
- opts: LoadOptions,
17
- ) => Promise<any> | any;
12
+ export type LoadFn = (req: Request, opts: LoadOptions) => Promise<any> | any;
18
13
 
19
14
  export type LoadOptions = {
20
15
  setProgress: (num: number) => void;
@@ -29,12 +24,7 @@ export default class PageLoader<More> {
29
24
 
30
25
  private loadingVersion: number;
31
26
 
32
- onLoaded: (
33
- resp: LoadResponse,
34
- req: Request,
35
- site: Site,
36
- more: More,
37
- ) => void;
27
+ onLoaded: (resp: LoadResponse, req: Request, more: More) => void;
38
28
  onProgress: (loading: boolean, progress?: number) => void;
39
29
  loadFn: LoadFn;
40
30
 
@@ -62,7 +52,7 @@ export default class PageLoader<More> {
62
52
  this.onProgress(false);
63
53
  }
64
54
 
65
- async load(req: Request, site: Site, more: More) {
55
+ async load(req: Request, more: More) {
66
56
  this.onProgress(true);
67
57
 
68
58
  const version = ++this.loadingVersion;
@@ -76,7 +66,7 @@ export default class PageLoader<More> {
76
66
 
77
67
  const resp: LoadResponse = { success: false, data: null };
78
68
  try {
79
- resp.data = await this.loadFn(req, site, { setProgress });
69
+ resp.data = await this.loadFn(req, { setProgress });
80
70
  resp.success = true;
81
71
  } catch (e) {
82
72
  resp.success = false;
@@ -91,18 +81,18 @@ export default class PageLoader<More> {
91
81
  return console.log('route changed quickly, ignoring response');
92
82
 
93
83
  this.onProgress(false);
94
- this.onLoaded(resp, req, site, more);
84
+ this.onLoaded(resp, req, more);
95
85
  }
96
86
 
97
87
  // you don't need to wait on this call
98
- async preload(req: Request, site: Site) {
88
+ async preload(req: Request) {
99
89
  const url = req.url.origin + req.url.pathname;
100
90
  if (this.preloadedUrls.has(url)) return;
101
91
 
102
92
  this.preloadedUrls.add(url);
103
93
 
104
94
  try {
105
- await this.loadFn(req, site, { setProgress: () => null });
95
+ await this.loadFn(req, { setProgress: () => null });
106
96
  } catch (_e) {
107
97
  console.log('preload failed');
108
98
  // retry at another time
@@ -10,6 +10,8 @@ export type RequestOptions = {
10
10
  index?: number;
11
11
  origin?: RouteOrigin;
12
12
  disableScroll?: boolean;
13
+ disableLoadData?: boolean;
14
+ statusCode?: number;
13
15
  };
14
16
 
15
17
  /**
@@ -24,31 +26,41 @@ export default class Request extends Route {
24
26
  */
25
27
  disableScroll: boolean;
26
28
 
29
+ /**
30
+ * Disable loading data
31
+ * @default false
32
+ */
33
+ disableLoadData: boolean;
34
+
35
+ /**
36
+ * The Status code that should be returned for a redirect
37
+ */
38
+ statusCode: number | null;
39
+
27
40
  /** @hidden */
28
41
  _renderBarrier: RenderBarrier;
29
42
 
30
43
  /**
31
44
  * Create a new Request
32
45
  */
33
- constructor(
34
- url: string | URL,
35
- site: Site | null,
36
- opts: RequestOptions = {},
37
- ) {
46
+ constructor(url: string | URL, site: Site, opts: RequestOptions = {}) {
38
47
  super(url, site, opts);
39
48
 
40
49
  this.disableScroll = opts.disableScroll ?? false;
50
+ this.disableLoadData = opts.disableLoadData ?? false;
51
+ this.statusCode = opts.statusCode ?? null;
41
52
  this._renderBarrier = new RenderBarrier();
42
53
  }
43
54
 
44
55
  /**
45
56
  * Create a Request from a Route
46
57
  */
47
- static fromRoute(route: Route) {
58
+ static fromRoute(route: Route, opts: RequestOptions = {}) {
48
59
  return new Request(route.url.href, route.site, {
49
60
  scrollY: route.scrollY ?? undefined,
50
61
  index: route.index,
51
62
  origin: route.origin,
63
+ ...opts,
52
64
  });
53
65
  }
54
66
 
@@ -93,6 +105,7 @@ export default class Request extends Route {
93
105
  index: this.index,
94
106
  origin: this.origin,
95
107
  disableScroll: this.disableScroll,
108
+ statusCode: this.statusCode ?? undefined,
96
109
  });
97
110
  }
98
111
 
@@ -106,6 +119,15 @@ export default class Request extends Route {
106
119
  origin: this.origin,
107
120
  });
108
121
  }
122
+
123
+ /** @hidden */
124
+ _updateOpts(opts: RequestOptions = {}) {
125
+ this.scrollY = opts.scrollY ?? this.scrollY;
126
+ this.index = opts.index ?? this.index;
127
+ this.origin = opts.origin ?? this.origin;
128
+ this.disableScroll = opts.disableScroll ?? this.disableScroll;
129
+ this.statusCode = opts.statusCode ?? this.statusCode;
130
+ }
109
131
  }
110
132
 
111
133
  export function isRequest(req: any): req is Request {