crelte 0.1.3 → 0.2.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.
Files changed (52) 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 +2 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +3 -3
  10. package/dist/init/client.d.ts.map +1 -1
  11. package/dist/init/client.js +5 -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 +13 -9
  25. package/dist/routing/InnerRouter.d.ts.map +1 -1
  26. package/dist/routing/InnerRouter.js +30 -35
  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 +9 -2
  31. package/dist/routing/Request.d.ts.map +1 -1
  32. package/dist/routing/Request.js +16 -1
  33. package/dist/routing/Route.d.ts +25 -12
  34. package/dist/routing/Route.d.ts.map +1 -1
  35. package/dist/routing/Route.js +34 -13
  36. package/dist/routing/Router.d.ts +5 -6
  37. package/dist/routing/Router.d.ts.map +1 -1
  38. package/dist/routing/Router.js +26 -34
  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 +17 -3
  43. package/src/init/client.ts +5 -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 +42 -39
  49. package/src/routing/PageLoader.ts +7 -17
  50. package/src/routing/Request.ts +20 -6
  51. package/src/routing/Route.ts +39 -15
  52. package/src/routing/Router.ts +33 -42
@@ -1,8 +1,8 @@
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';
5
- import Route from './Route.js';
4
+ import Request, { isRequest, RequestOptions } from './Request.js';
5
+ import Route, { RouteOptions } from './Route.js';
6
6
 
7
7
  export type InnerRouterOpts = {
8
8
  preloadOnMouseOver: boolean;
@@ -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,18 @@ 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);
65
+ const req = this.targetToRequest(window.location.href);
66
+ req._fillFromState(window.history.state);
63
67
 
64
- route.origin = 'init';
68
+ req.origin = 'init';
65
69
 
66
- if (route.search.get('x-craft-live-preview')) {
67
- route.origin = 'live-preview-init';
70
+ if (req.search.get('x-craft-live-preview')) {
71
+ req.origin = 'live-preview-init';
68
72
  }
69
73
 
70
74
  window.history.scrollRestoration = 'manual';
71
75
 
72
- this.open(route, false);
76
+ this.open(req, {}, false);
73
77
  }
74
78
 
75
79
  /**
@@ -80,8 +84,7 @@ export default class InnerRouter {
80
84
  /**
81
85
  * Get a site and if possible use the accept lang header.
82
86
  *
83
- * @param {(string|null)} [acceptLang=null] Accept Language header.
84
- * @return {Site}
87
+ * @param acceptLang Accept Language header.
85
88
  */
86
89
  siteByAcceptLang(acceptLang: string | null = null): Site {
87
90
  if (!acceptLang) return this.defaultSite();
@@ -125,7 +128,7 @@ export default class InnerRouter {
125
128
  * Get the default site
126
129
  */
127
130
  defaultSite(): Site {
128
- return this.sites[0];
131
+ return this.sites.find(s => s.primary) ?? this.sites[0];
129
132
  }
130
133
 
131
134
  /**
@@ -141,10 +144,15 @@ export default class InnerRouter {
141
144
  * @param target
142
145
  * @return Returns null if the url does not match our host (the protocol get's ignored)
143
146
  */
144
- targetToRequest(target: string | URL | Route | Request): Request {
147
+ targetToRequest(
148
+ target: string | URL | Route | Request,
149
+ opts: RequestOptions = {},
150
+ ): Request {
145
151
  if (typeof target === 'string') {
146
152
  if (target.startsWith('/')) {
147
- const site = this.site;
153
+ // todo should we use the language matching or throw if the route does not
154
+ // exists
155
+ const site = this.route?.site ?? this.defaultSite();
148
156
  target = new URL(site.uri + target, site.url);
149
157
  } else {
150
158
  target = new URL(target);
@@ -156,9 +164,10 @@ export default class InnerRouter {
156
164
  }
157
165
 
158
166
  if (!isRequest(target)) {
159
- return Request.fromRoute(target);
167
+ return Request.fromRoute(target, opts);
160
168
  }
161
169
 
170
+ target._updateOpts(opts);
162
171
  return target;
163
172
  }
164
173
 
@@ -170,7 +179,7 @@ export default class InnerRouter {
170
179
  */
171
180
  routeFromUrl(fullUrl: URL): Route {
172
181
  // strip stuff we dont need from url
173
- const route = new Route(fullUrl, null);
182
+ const route = new Route(fullUrl, null!);
174
183
  const url = route.url;
175
184
 
176
185
  let site: Site | null = null;
@@ -193,7 +202,9 @@ export default class InnerRouter {
193
202
  site = s;
194
203
  }
195
204
 
196
- route.site = site;
205
+ // todo should we throw if we can't find a site
206
+ // or use the site which matches the language
207
+ route.site = site ?? this.defaultSite();
197
208
 
198
209
  return route;
199
210
  }
@@ -284,7 +295,7 @@ export default class InnerRouter {
284
295
  // route since it is now already the new route
285
296
  this.route = null;
286
297
 
287
- this.open(route, false);
298
+ this.open(route, {}, false);
288
299
  });
289
300
  }
290
301
 
@@ -294,8 +305,12 @@ export default class InnerRouter {
294
305
  * @param route a route object or an url or uri, never input the same route object again
295
306
  * @param pushState if true pushed the state to the window.history
296
307
  */
297
- open(target: string | URL | Route | Request, pushState: boolean = true) {
298
- const req = this.targetToRequest(target);
308
+ open(
309
+ target: string | URL | Route | Request,
310
+ opts: RouteOptions = {},
311
+ pushState: boolean = true,
312
+ ) {
313
+ const req = this.targetToRequest(target, opts);
299
314
 
300
315
  const current = this.route;
301
316
  if (current) {
@@ -321,13 +336,13 @@ export default class InnerRouter {
321
336
  // @ts-ignore
322
337
  import.meta.env.SSR
323
338
  ) {
324
- this.history.open(req.url.href);
339
+ this.history.open(req);
325
340
  return;
326
341
  }
327
342
 
328
343
  if (pushState) {
329
344
  req.index = (current?.index ?? 0) + 1;
330
- this.onRoute(req, req.site ?? this.site, () => {
345
+ this.onRoute(req, () => {
331
346
  this.pushState(req.toRoute());
332
347
  });
333
348
  } else {
@@ -345,9 +360,8 @@ export default class InnerRouter {
345
360
  */
346
361
  setRoute(req: Request) {
347
362
  this.route = req.toRoute();
348
- if (req.site) this.site = req.site;
349
363
 
350
- this.onRoute(req, this.site, () => {});
364
+ this.onRoute(req, () => {});
351
365
  }
352
366
 
353
367
  /**
@@ -368,7 +382,6 @@ export default class InnerRouter {
368
382
  );
369
383
 
370
384
  this.route = route;
371
- if (route.site) this.site = route.site;
372
385
  }
373
386
 
374
387
  /**
@@ -386,7 +399,6 @@ export default class InnerRouter {
386
399
  );
387
400
 
388
401
  this.route = route;
389
- if (route.site) this.site = route.site;
390
402
  }
391
403
 
392
404
  /**
@@ -398,21 +410,12 @@ export default class InnerRouter {
398
410
  */
399
411
  preload(target: string | URL | Route | Request) {
400
412
  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
413
  const current = this.route;
410
- const site = req.site ?? this.site;
411
414
 
412
415
  // if the origin matches, the route will be able to be load
413
416
  // so let's preload it
414
417
  if (current && current.url.origin === req.url.origin) {
415
- this.onPreload(req, site);
418
+ this.onPreload(req);
416
419
  }
417
420
  }
418
421
 
@@ -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,7 @@ export type RequestOptions = {
10
10
  index?: number;
11
11
  origin?: RouteOrigin;
12
12
  disableScroll?: boolean;
13
+ statusCode?: number;
13
14
  };
14
15
 
15
16
  /**
@@ -24,31 +25,34 @@ export default class Request extends Route {
24
25
  */
25
26
  disableScroll: boolean;
26
27
 
28
+ /**
29
+ * The Status code that should be returned for a redirect
30
+ */
31
+ statusCode: number | null;
32
+
27
33
  /** @hidden */
28
34
  _renderBarrier: RenderBarrier;
29
35
 
30
36
  /**
31
37
  * Create a new Request
32
38
  */
33
- constructor(
34
- url: string | URL,
35
- site: Site | null,
36
- opts: RequestOptions = {},
37
- ) {
39
+ constructor(url: string | URL, site: Site, opts: RequestOptions = {}) {
38
40
  super(url, site, opts);
39
41
 
40
42
  this.disableScroll = opts.disableScroll ?? false;
43
+ this.statusCode = opts.statusCode ?? null;
41
44
  this._renderBarrier = new RenderBarrier();
42
45
  }
43
46
 
44
47
  /**
45
48
  * Create a Request from a Route
46
49
  */
47
- static fromRoute(route: Route) {
50
+ static fromRoute(route: Route, opts: RequestOptions = {}) {
48
51
  return new Request(route.url.href, route.site, {
49
52
  scrollY: route.scrollY ?? undefined,
50
53
  index: route.index,
51
54
  origin: route.origin,
55
+ ...opts,
52
56
  });
53
57
  }
54
58
 
@@ -93,6 +97,7 @@ export default class Request extends Route {
93
97
  index: this.index,
94
98
  origin: this.origin,
95
99
  disableScroll: this.disableScroll,
100
+ statusCode: this.statusCode ?? undefined,
96
101
  });
97
102
  }
98
103
 
@@ -106,6 +111,15 @@ export default class Request extends Route {
106
111
  origin: this.origin,
107
112
  });
108
113
  }
114
+
115
+ /** @hidden */
116
+ _updateOpts(opts: RequestOptions = {}) {
117
+ this.scrollY = opts.scrollY ?? this.scrollY;
118
+ this.index = opts.index ?? this.index;
119
+ this.origin = opts.origin ?? this.origin;
120
+ this.disableScroll = opts.disableScroll ?? this.disableScroll;
121
+ this.statusCode = opts.statusCode ?? this.statusCode;
122
+ }
109
123
  }
110
124
 
111
125
  export function isRequest(req: any): req is Request {
@@ -38,9 +38,16 @@ export default class Route {
38
38
  url: URL;
39
39
 
40
40
  /**
41
- * The site of the route if it could be defined
41
+ * The site of the route
42
+ *
43
+ * ## Note
44
+ * The site might not always match with the current route
45
+ * but be the site default site or one that matches the
46
+ * users language.
47
+ *
48
+ * If that is important call `route.siteMatches()` to verify
42
49
  */
43
- site: Site | null;
50
+ site: Site;
44
51
 
45
52
  /**
46
53
  * The scroll position of the current route
@@ -61,7 +68,7 @@ export default class Route {
61
68
  /**
62
69
  * Creates a new Route
63
70
  */
64
- constructor(url: string | URL, site: Site | null, opts: RouteOptions = {}) {
71
+ constructor(url: string | URL, site: Site, opts: RouteOptions = {}) {
65
72
  this.url = new URL(url);
66
73
 
67
74
  this.site = site;
@@ -77,17 +84,17 @@ export default class Route {
77
84
  *
78
85
  * ## Example
79
86
  * ```
80
- * const route = new Route('https://example.com/foo/bar/', null);
81
- * console.log(route.uri); // '/foo/bar'
87
+ * const site = _; // site with url https://example.com/fo
88
+ * const route = new Route('https://example.com/foo/bar/', site);
89
+ * console.log(route.uri); // '/bar'
82
90
  *
83
- * const site = _; // site with url https://example.com/foo
84
- * const route2 = new Route('https://example.com/foo/bar/?a=1', site);
85
- * console.log(route2.uri); // '/bar'
91
+ * const site2 = _; // site with url https://example.com/other
92
+ * const route2 = new Route('https://example.com/foo/bar/?a=1', site2);
93
+ * console.log(route2.uri); // '/foo/bar'
86
94
  * ```
87
95
  */
88
96
  get uri(): string {
89
- // todo check if this is correct
90
- if (this.site) {
97
+ if (this.siteMatches()) {
91
98
  return trimSlashEnd(
92
99
  this.url.pathname.substring(this.site.uri.length),
93
100
  );
@@ -103,16 +110,17 @@ export default class Route {
103
110
  *
104
111
  * ## Example
105
112
  * ```
113
+ * const site = _; // site with url https://example.com/foo
106
114
  * const route = new Route('https://example.com/foo/bar/', null);
107
- * console.log(route.baseUrl); // 'https://example.com'
115
+ * console.log(route.baseUrl); // 'https://example.com/foo'
108
116
  *
109
- * const site = _; // site with url https://example.com/foo
110
- * const route2 = new Route('https://example.com/foo/bar/', site);
111
- * console.log(route2.baseUrl); // 'https://example.com/foo'
117
+ * const site2 = _; // site with url https://example.com/other
118
+ * const route2 = new Route('https://example.com/foo/bar/', site2);
119
+ * console.log(route2.baseUrl); // 'https://example.com'
112
120
  * ```
113
121
  */
114
122
  get baseUrl(): string {
115
- if (this.site) return trimSlashEnd(this.site.url.href);
123
+ if (this.siteMatches()) return trimSlashEnd(this.site.url.href);
116
124
 
117
125
  return this.url.origin;
118
126
  }
@@ -146,6 +154,22 @@ export default class Route {
146
154
  return this.url.hash;
147
155
  }
148
156
 
157
+ /**
158
+ * Returns if the site matches the url
159
+ */
160
+ siteMatches(): boolean {
161
+ if (this.url.origin !== this.site.url.origin) return false;
162
+
163
+ // now we need to validate the pathname we should make sure both end with a slash
164
+ // todo can we do this better?
165
+
166
+ // make sure that urls like pathname: /abcbc and site: /abc don't match
167
+ return (this.url.pathname + '/').startsWith(
168
+ // uri never returns a slash at the end
169
+ this.site.uri + '/',
170
+ );
171
+ }
172
+
149
173
  /**
150
174
  * Checks if the route is equal to another route
151
175
  *
@@ -5,7 +5,7 @@ import PageLoader, { LoadFn, LoadResponse } from './PageLoader.js';
5
5
  import { ServerHistory } from './History.js';
6
6
  import { Readable, Writable } from 'crelte-std/stores';
7
7
  import { Listeners } from 'crelte-std/sync';
8
- import Request from './Request.js';
8
+ import Request, { RequestOptions } from './Request.js';
9
9
 
10
10
  export type RouterOptions = {
11
11
  preloadOnMouseOver?: boolean;
@@ -28,7 +28,6 @@ type Internal = {
28
28
  onLoaded: (
29
29
  success: boolean,
30
30
  req: Request,
31
- site: Site,
32
31
  // call ready once your ready to update the dom
33
32
  // this makes sure we trigger a route and site update
34
33
  // almost at the same moment and probably the same tick
@@ -50,7 +49,6 @@ type ServerInited = {
50
49
  // redirect to the route url
51
50
  redirect: boolean;
52
51
  req: Request;
53
- site: Site;
54
52
  props: any;
55
53
  };
56
54
 
@@ -80,9 +78,9 @@ export default class Router {
80
78
  */
81
79
  private _loadingProgress: Writable<number>;
82
80
 
83
- private _onRouteEv: Listeners<[Route, Site]>;
81
+ private _onRouteEv: Listeners<[Route]>;
84
82
 
85
- private _onRequest: Listeners<[Request, Site]>;
83
+ private _onRequest: Listeners<[Request]>;
86
84
 
87
85
  /** @hidden */
88
86
  _internal: Internal;
@@ -119,14 +117,14 @@ export default class Router {
119
117
  initServer: (url, acceptLang) => this._initServer(url, acceptLang),
120
118
  };
121
119
 
122
- this.inner.onRoute = (route, site, changeHistory) =>
123
- this._onRoute(route, site, changeHistory);
124
- this.inner.onPreload = (route, site) => this._onPreload(route, site);
120
+ this.inner.onRoute = (route, changeHistory) =>
121
+ this._onRoute(route, changeHistory);
122
+ this.inner.onPreload = route => this._onPreload(route);
125
123
 
126
- this.pageLoader.onLoaded = (resp, req, site, more) =>
127
- this._onLoaded(resp, req, site, more);
128
- this.pageLoader.loadFn = (req, site, opts) =>
129
- this._internal.onLoad(req, site, opts);
124
+ this.pageLoader.onLoaded = (resp, req, more) =>
125
+ this._onLoaded(resp, req, more);
126
+ this.pageLoader.loadFn = (req, opts) =>
127
+ this._internal.onLoad(req, opts);
130
128
  this.pageLoader.onProgress = (loading, progress) =>
131
129
  this._onProgress(loading, progress);
132
130
  }
@@ -184,8 +182,8 @@ export default class Router {
184
182
  * // the following page will be opened https://example.com/de/foo/bar
185
183
  * ```
186
184
  */
187
- open(target: string | URL | Route) {
188
- this.inner.open(target);
185
+ open(target: string | URL | Route, opts: RequestOptions = {}) {
186
+ this.inner.open(target, opts);
189
187
  }
190
188
 
191
189
  /**
@@ -209,6 +207,7 @@ export default class Router {
209
207
  pushState(route: Route) {
210
208
  this.pageLoader.discard();
211
209
  this.inner.pushState(route);
210
+ this.destroyRequest();
212
211
  this.setNewRoute(route);
213
212
  }
214
213
 
@@ -232,6 +231,7 @@ export default class Router {
232
231
  replaceState(route: Route) {
233
232
  this.pageLoader.discard();
234
233
  this.inner.replaceState(route);
234
+ this.destroyRequest();
235
235
  this.setNewRoute(route);
236
236
  }
237
237
 
@@ -264,7 +264,7 @@ export default class Router {
264
264
  *
265
265
  * @returns a function to remove the listener
266
266
  */
267
- onRoute(fn: (route: Route, site: Site) => void): () => void {
267
+ onRoute(fn: (route: Route) => void): () => void {
268
268
  return this._onRouteEv.add(fn);
269
269
  }
270
270
 
@@ -275,17 +275,16 @@ export default class Router {
275
275
  *
276
276
  * @returns a function to remove the listener
277
277
  */
278
- onRequest(fn: (req: Request, site: Site) => void): () => void {
278
+ onRequest(fn: (req: Request) => void): () => void {
279
279
  return this._onRequest.add(fn);
280
280
  }
281
281
 
282
282
  private setNewRoute(route: Route) {
283
- this.destroyRequest();
284
-
285
283
  this._route.setSilent(route);
286
- if (route.site) this._site.setSilent(route.site);
284
+ const siteChanged = this.site.get()?.id !== route.site.id;
285
+ this._site.setSilent(route.site);
287
286
  this._route.notify();
288
- if (route.site) this._site.notify();
287
+ if (siteChanged) this._site.notify();
289
288
  }
290
289
 
291
290
  private async _initClient() {
@@ -299,7 +298,7 @@ export default class Router {
299
298
  this.inner.initServer();
300
299
 
301
300
  const prom: Promise<ServerInited> = new Promise(resolve => {
302
- this._internal.onLoaded = (success, req, site, ready) => {
301
+ this._internal.onLoaded = (success, req, ready) => {
303
302
  const props = ready();
304
303
  this._internal.onLoaded = () => {};
305
304
 
@@ -307,7 +306,6 @@ export default class Router {
307
306
  success,
308
307
  redirect: false,
309
308
  req,
310
- site,
311
309
  props,
312
310
  });
313
311
  };
@@ -318,14 +316,13 @@ export default class Router {
318
316
 
319
317
  // let's see if the url matches any route and site
320
318
  // if not let's redirect to the site which matches the acceptLang
321
- if (!route.site) {
319
+ if (!route.siteMatches()) {
322
320
  const site = this.inner.siteByAcceptLang(acceptLang);
323
321
 
324
322
  return {
325
323
  success: true,
326
324
  redirect: true,
327
325
  req: new Request(site.url, site),
328
- site,
329
326
  props: {},
330
327
  };
331
328
  }
@@ -335,14 +332,13 @@ export default class Router {
335
332
  const resp = await prom;
336
333
 
337
334
  const hist = this.inner.history as ServerHistory;
338
- if (hist.url) {
339
- const nRoute = new Route(hist.url, null);
340
- if (!route.eq(nRoute)) {
335
+ if (hist.url || hist.req) {
336
+ const nReq = this.inner.targetToRequest(hist.req ?? hist.url!);
337
+ if (!route.eq(nReq)) {
341
338
  return {
342
339
  success: true,
343
340
  redirect: true,
344
- req: Request.fromRoute(nRoute),
345
- site: route.site!,
341
+ req: nReq,
346
342
  props: {},
347
343
  };
348
344
  }
@@ -351,7 +347,7 @@ export default class Router {
351
347
  return resp;
352
348
  }
353
349
 
354
- private _onRoute(req: Request, site: Site, changeHistory: () => void) {
350
+ private _onRoute(req: Request, changeHistory: () => void) {
355
351
  this.destroyRequest();
356
352
 
357
353
  this._request = req;
@@ -361,10 +357,10 @@ export default class Router {
361
357
  throw new Error('render barrier is already open');
362
358
  }
363
359
 
364
- this._onRequest.trigger(req, site);
360
+ this._onRequest.trigger(req);
365
361
 
366
362
  // route prepared
367
- this.pageLoader.load(req, site, { changeHistory });
363
+ this.pageLoader.load(req, { changeHistory });
368
364
  }
369
365
 
370
366
  private destroyRequest() {
@@ -374,14 +370,13 @@ export default class Router {
374
370
  this._request = null;
375
371
  }
376
372
 
377
- private _onPreload(req: Request, site: Site) {
378
- this.pageLoader.preload(req, site);
373
+ private _onPreload(req: Request) {
374
+ this.pageLoader.preload(req);
379
375
  }
380
376
 
381
377
  private async _onLoaded(
382
378
  resp: LoadResponse,
383
379
  req: Request,
384
- site: Site,
385
380
  more: LoadedMore,
386
381
  ) {
387
382
  // check if the render was cancelled
@@ -395,16 +390,12 @@ export default class Router {
395
390
  const route = req.toRoute();
396
391
 
397
392
  const updateRoute = () => {
398
- this._route.setSilent(route);
399
- const siteChanged = this.site.get()?.id !== site.id;
400
- this._site.setSilent(site);
401
- this._route.notify();
402
- if (siteChanged) this._site.notify();
393
+ this.setNewRoute(route);
403
394
 
404
- this._onRouteEv.trigger(route.clone(), site);
395
+ this._onRouteEv.trigger(route.clone());
405
396
  };
406
397
 
407
- this._internal.onLoaded(resp.success, req, site, () => {
398
+ this._internal.onLoaded(resp.success, req, () => {
408
399
  updateRoute();
409
400
  return resp.data;
410
401
  });