crelte 0.1.2 → 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 (58) 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 +35 -14
  36. package/dist/routing/Router.d.ts +5 -7
  37. package/dist/routing/Router.d.ts.map +1 -1
  38. package/dist/routing/Router.js +26 -37
  39. package/dist/routing/Site.js +1 -1
  40. package/dist/routing/utils.d.ts +2 -0
  41. package/dist/routing/utils.d.ts.map +1 -0
  42. package/dist/routing/utils.js +3 -0
  43. package/package.json +3 -2
  44. package/src/CrelteRequest.ts +14 -19
  45. package/src/graphql/GraphQl.ts +5 -2
  46. package/src/index.ts +17 -3
  47. package/src/init/client.ts +5 -10
  48. package/src/init/server.ts +31 -11
  49. package/src/init/shared.ts +4 -4
  50. package/src/loadData/index.ts +47 -15
  51. package/src/routing/History.ts +12 -5
  52. package/src/routing/InnerRouter.ts +42 -39
  53. package/src/routing/PageLoader.ts +7 -17
  54. package/src/routing/Request.ts +20 -6
  55. package/src/routing/Route.ts +40 -16
  56. package/src/routing/Router.ts +33 -46
  57. package/src/routing/Site.ts +1 -1
  58. package/src/routing/utils.ts +3 -0
@@ -1,4 +1,3 @@
1
- import Route from './Route.js';
2
1
  import InnerRouter from './InnerRouter.js';
3
2
  import PageLoader from './PageLoader.js';
4
3
  import { Writable } from 'crelte-std/stores';
@@ -8,9 +7,6 @@ const defaultRouterOpts = {
8
7
  preloadOnMouseOver: false,
9
8
  deubgTiming: false,
10
9
  };
11
- export function trimSlashEnd(str) {
12
- return str.endsWith('/') ? str.substring(0, str.length - 1) : str;
13
- }
14
10
  // Make sure route and nextRoute are not the same object as _inner.route
15
11
  export default class Router {
16
12
  /**
@@ -61,10 +57,10 @@ export default class Router {
61
57
  initClient: () => this._initClient(),
62
58
  initServer: (url, acceptLang) => this._initServer(url, acceptLang),
63
59
  };
64
- this.inner.onRoute = (route, site, changeHistory) => this._onRoute(route, site, changeHistory);
65
- this.inner.onPreload = (route, site) => this._onPreload(route, site);
66
- this.pageLoader.onLoaded = (resp, req, site, more) => this._onLoaded(resp, req, site, more);
67
- this.pageLoader.loadFn = (req, site, opts) => this._internal.onLoad(req, site, opts);
60
+ this.inner.onRoute = (route, changeHistory) => this._onRoute(route, changeHistory);
61
+ this.inner.onPreload = route => this._onPreload(route);
62
+ this.pageLoader.onLoaded = (resp, req, more) => this._onLoaded(resp, req, more);
63
+ this.pageLoader.loadFn = (req, opts) => this._internal.onLoad(req, opts);
68
64
  this.pageLoader.onProgress = (loading, progress) => this._onProgress(loading, progress);
69
65
  }
70
66
  /**
@@ -115,8 +111,8 @@ export default class Router {
115
111
  * // the following page will be opened https://example.com/de/foo/bar
116
112
  * ```
117
113
  */
118
- open(target) {
119
- this.inner.open(target);
114
+ open(target, opts = {}) {
115
+ this.inner.open(target, opts);
120
116
  }
121
117
  /**
122
118
  * This pushes the state of the route without triggering an event
@@ -139,6 +135,7 @@ export default class Router {
139
135
  pushState(route) {
140
136
  this.pageLoader.discard();
141
137
  this.inner.pushState(route);
138
+ this.destroyRequest();
142
139
  this.setNewRoute(route);
143
140
  }
144
141
  /**
@@ -161,6 +158,7 @@ export default class Router {
161
158
  replaceState(route) {
162
159
  this.pageLoader.discard();
163
160
  this.inner.replaceState(route);
161
+ this.destroyRequest();
164
162
  this.setNewRoute(route);
165
163
  }
166
164
  /**
@@ -203,12 +201,11 @@ export default class Router {
203
201
  return this._onRequest.add(fn);
204
202
  }
205
203
  setNewRoute(route) {
206
- this.destroyRequest();
207
204
  this._route.setSilent(route);
208
- if (route.site)
209
- this._site.setSilent(route.site);
205
+ const siteChanged = this.site.get()?.id !== route.site.id;
206
+ this._site.setSilent(route.site);
210
207
  this._route.notify();
211
- if (route.site)
208
+ if (siteChanged)
212
209
  this._site.notify();
213
210
  }
214
211
  async _initClient() {
@@ -217,14 +214,13 @@ export default class Router {
217
214
  async _initServer(url, acceptLang) {
218
215
  this.inner.initServer();
219
216
  const prom = new Promise(resolve => {
220
- this._internal.onLoaded = (success, req, site, ready) => {
217
+ this._internal.onLoaded = (success, req, ready) => {
221
218
  const props = ready();
222
219
  this._internal.onLoaded = () => { };
223
220
  resolve({
224
221
  success,
225
222
  redirect: false,
226
223
  req,
227
- site,
228
224
  props,
229
225
  });
230
226
  };
@@ -233,43 +229,41 @@ export default class Router {
233
229
  route.origin = 'init';
234
230
  // let's see if the url matches any route and site
235
231
  // if not let's redirect to the site which matches the acceptLang
236
- if (!route.site) {
232
+ if (!route.siteMatches()) {
237
233
  const site = this.inner.siteByAcceptLang(acceptLang);
238
234
  return {
239
235
  success: true,
240
236
  redirect: true,
241
237
  req: new Request(site.url, site),
242
- site,
243
238
  props: {},
244
239
  };
245
240
  }
246
241
  this.inner.setRoute(route);
247
242
  const resp = await prom;
248
243
  const hist = this.inner.history;
249
- if (hist.url) {
250
- const nRoute = new Route(hist.url, null);
251
- if (!route.eq(nRoute)) {
244
+ if (hist.url || hist.req) {
245
+ const nReq = this.inner.targetToRequest(hist.req ?? hist.url);
246
+ if (!route.eq(nReq)) {
252
247
  return {
253
248
  success: true,
254
249
  redirect: true,
255
- req: Request.fromRoute(nRoute),
256
- site: route.site,
250
+ req: nReq,
257
251
  props: {},
258
252
  };
259
253
  }
260
254
  }
261
255
  return resp;
262
256
  }
263
- _onRoute(req, site, changeHistory) {
257
+ _onRoute(req, changeHistory) {
264
258
  this.destroyRequest();
265
259
  this._request = req;
266
260
  const barrier = req._renderBarrier;
267
261
  if (barrier.isOpen()) {
268
262
  throw new Error('render barrier is already open');
269
263
  }
270
- this._onRequest.trigger(req, site);
264
+ this._onRequest.trigger(req);
271
265
  // route prepared
272
- this.pageLoader.load(req, site, { changeHistory });
266
+ this.pageLoader.load(req, { changeHistory });
273
267
  }
274
268
  destroyRequest() {
275
269
  if (!this._request)
@@ -277,10 +271,10 @@ export default class Router {
277
271
  this._request._renderBarrier.cancel();
278
272
  this._request = null;
279
273
  }
280
- _onPreload(req, site) {
281
- this.pageLoader.preload(req, site);
274
+ _onPreload(req) {
275
+ this.pageLoader.preload(req);
282
276
  }
283
- async _onLoaded(resp, req, site, more) {
277
+ async _onLoaded(resp, req, more) {
284
278
  // check if the render was cancelled
285
279
  if (await req._renderBarrier.ready())
286
280
  return;
@@ -290,15 +284,10 @@ export default class Router {
290
284
  more.changeHistory();
291
285
  const route = req.toRoute();
292
286
  const updateRoute = () => {
293
- this._route.setSilent(route);
294
- const siteChanged = this.site.get()?.id !== site.id;
295
- this._site.setSilent(site);
296
- this._route.notify();
297
- if (siteChanged)
298
- this._site.notify();
299
- this._onRouteEv.trigger(route.clone(), site);
287
+ this.setNewRoute(route);
288
+ this._onRouteEv.trigger(route.clone());
300
289
  };
301
- this._internal.onLoaded(resp.success, req, site, () => {
290
+ this._internal.onLoaded(resp.success, req, () => {
302
291
  updateRoute();
303
292
  return resp.data;
304
293
  });
@@ -1,4 +1,4 @@
1
- import { trimSlashEnd } from './Router.js';
1
+ import { trimSlashEnd } from './utils.js';
2
2
  /**
3
3
  * A Craft Site
4
4
  */
@@ -0,0 +1,2 @@
1
+ export declare function trimSlashEnd(str: string): string;
2
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../src/routing/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,UAEvC"}
@@ -0,0 +1,3 @@
1
+ export function trimSlashEnd(str) {
2
+ return str.endsWith('/') ? str.substring(0, str.length - 1) : str;
3
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crelte",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "author": "Crelte <support@crelte.com>",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -74,6 +74,7 @@
74
74
  "@sveltejs/vite-plugin-svelte": "^3.0.0",
75
75
  "svelte-check": "^4.1.4",
76
76
  "typescript-svelte-plugin": "^0.3.45",
77
- "vitest": "^2.0.0"
77
+ "vitest": "^2.0.0",
78
+ "vite": "^5.0"
78
79
  }
79
80
  }
@@ -11,19 +11,12 @@ export default class CrelteRequest extends Crelte {
11
11
  */
12
12
  req: Request;
13
13
 
14
- /**
15
- * The current site
16
- */
17
- site: Site;
18
-
19
14
  private innerGlobals: Map<string, any>;
20
15
 
21
- /// requires a site if the route does not contain a site
22
- constructor(inner: Crelte, req: Request, site: Site) {
16
+ constructor(inner: Crelte, req: Request) {
23
17
  super(inner);
24
18
 
25
19
  this.req = req;
26
- this.site = site;
27
20
  this.innerGlobals = new Map();
28
21
  }
29
22
 
@@ -37,24 +30,14 @@ export default class CrelteRequest extends Crelte {
37
30
  * If you provide a route it must contain a site or you must
38
31
  * provide one,
39
32
  */
40
- static fromCrelte(
41
- inner: Crelte,
42
- req?: Route | Request,
43
- site?: Site,
44
- ): CrelteRequest {
33
+ static fromCrelte(inner: Crelte, req?: Route | Request): CrelteRequest {
45
34
  if (!req) {
46
35
  req = inner.router.route.get();
47
36
  }
48
37
 
49
- if (!site) {
50
- if (!req.site) throw new Error('site is required');
51
- site = req.site;
52
- }
53
-
54
38
  return new CrelteRequest(
55
39
  inner,
56
40
  req instanceof Request ? req : Request.fromRoute(req),
57
- site,
58
41
  );
59
42
  }
60
43
 
@@ -66,6 +49,18 @@ export default class CrelteRequest extends Crelte {
66
49
  return this.req;
67
50
  }
68
51
 
52
+ /**
53
+ * Easy access to this.req.site
54
+ *
55
+ * ## Note
56
+ * The site might not always match with the current route
57
+ * but be the site default site or one that matches the
58
+ * users language.
59
+ */
60
+ get site(): Site {
61
+ return this.req.site;
62
+ }
63
+
69
64
  /**
70
65
  * returns a globalSet
71
66
  *
@@ -70,7 +70,9 @@ export type GraphQlOptions = {
70
70
  */
71
71
  export type GraphQlRequestOptions = {
72
72
  path?: string;
73
- route?: Route;
73
+ // !! the route here might not contain a site even if the types
74
+ // says it does. CrelteServer does not know about site
75
+ route?: Route | URL;
74
76
  ignoreStatusCode?: boolean;
75
77
  previewToken?: string;
76
78
  siteToken?: string;
@@ -124,7 +126,8 @@ export default class GraphQl {
124
126
  opts: GraphQlRequestOptions = {},
125
127
  ): Promise<unknown> {
126
128
  if (opts.route) {
127
- const search = opts.route.search;
129
+ const search =
130
+ (opts.route as URL).searchParams ?? opts.route.search;
128
131
 
129
132
  // todo should variables contain siteId
130
133
  // or maybe gql should detect loadData and add it there
package/src/index.ts CHANGED
@@ -9,8 +9,22 @@ import CrelteRequest from './CrelteRequest.js';
9
9
  import type { Global, GlobalData } from './loadData/Globals.js';
10
10
  import type { Cookies } from './cookies/index.js';
11
11
  import type { Readable } from 'crelte-std/stores';
12
+ import {
13
+ LoadData,
14
+ LoadDataArray,
15
+ LoadDataFn,
16
+ LoadDataObj,
17
+ } from './loadData/index.js';
12
18
 
13
- export { Crelte, CrelteRequest, type QueryOptions };
19
+ export {
20
+ Crelte,
21
+ CrelteRequest,
22
+ type QueryOptions,
23
+ type LoadData,
24
+ type LoadDataFn,
25
+ type LoadDataObj,
26
+ type LoadDataArray,
27
+ };
14
28
 
15
29
  /**
16
30
  * Get Crelte from the current context
@@ -137,8 +151,8 @@ export function getCookies(): Cookies {
137
151
  */
138
152
  export function onRequest(fn: (cr: CrelteRequest) => void) {
139
153
  const crelte = getCrelte();
140
- const rmListener = crelte.router.onRequest((req, site) => {
141
- fn(new CrelteRequest(crelte, req, site));
154
+ const rmListener = crelte.router.onRequest(req => {
155
+ fn(new CrelteRequest(crelte, req));
142
156
  });
143
157
 
144
158
  onDestroy(rmListener);
@@ -131,8 +131,8 @@ export function main(data: MainData) {
131
131
 
132
132
  // setup load Data
133
133
 
134
- crelte.router._internal.onLoad = (req, site, opts) => {
135
- const cr = new CrelteRequest(crelte, req, site);
134
+ crelte.router._internal.onLoad = (req, opts) => {
135
+ const cr = new CrelteRequest(crelte, req);
136
136
  return loadFn(cr, data.app, data.entryQuery, data.globalQuery, opts);
137
137
  };
138
138
 
@@ -154,12 +154,7 @@ export function main(data: MainData) {
154
154
  };
155
155
 
156
156
  let firstLoad = true;
157
- crelte.router._internal.onLoaded = async (
158
- success,
159
- req,
160
- site,
161
- readyForProps,
162
- ) => {
157
+ crelte.router._internal.onLoaded = async (success, req, readyForProps) => {
163
158
  const isFirstLoad = firstLoad;
164
159
  firstLoad = false;
165
160
 
@@ -177,13 +172,13 @@ export function main(data: MainData) {
177
172
  return handleLoadError(readyForProps());
178
173
  }
179
174
 
180
- const cr = new CrelteRequest(crelte, req, site);
175
+ const cr = new CrelteRequest(crelte, req);
181
176
 
182
177
  const startTime = data.debugTiming ? Date.now() : null;
183
178
  let render = async () => {
184
179
  // we should trigger the route update here
185
180
  pluginsBeforeRender(cr);
186
- crelte.globals._updateSiteId(site.id);
181
+ crelte.globals._updateSiteId(cr.site.id);
187
182
  updateAppProps(readyForProps());
188
183
 
189
184
  await tick();
@@ -16,6 +16,8 @@ export type ServerData = {
16
16
  craftWeb: string;
17
17
  viteEnv: Map<string, string>;
18
18
  cookies?: string;
19
+ readSitesCache?: () => Promise<any>;
20
+ writeSitesCache?: (data: any) => Promise<void>;
19
21
  };
20
22
 
21
23
  /**
@@ -85,7 +87,7 @@ export async function main(data: MainData): Promise<{
85
87
  const cookies = data.serverData.cookies ?? '';
86
88
  builder.setupCookies(cookies);
87
89
 
88
- const csites = await loadSites(builder);
90
+ const csites = await loadSites(builder, data.serverData);
89
91
  builder.ssrCache.set('crelteSites', csites);
90
92
  builder.setupRouter(csites);
91
93
 
@@ -96,12 +98,12 @@ export async function main(data: MainData): Promise<{
96
98
 
97
99
  // setup load Data
98
100
 
99
- crelte.router._internal.onLoad = (req, site) => {
100
- const cr = new CrelteRequest(crelte, req, site);
101
+ crelte.router._internal.onLoad = req => {
102
+ const cr = new CrelteRequest(crelte, req);
101
103
  return loadFn(cr, data.app, data.entryQuery, data.globalQuery);
102
104
  };
103
105
 
104
- const { success, redirect, req, site, props } =
106
+ const { success, redirect, req, props } =
105
107
  await crelte.router._internal.initServer(
106
108
  data.serverData.url,
107
109
  data.serverData.acceptLang,
@@ -110,7 +112,7 @@ export async function main(data: MainData): Promise<{
110
112
 
111
113
  if (redirect) {
112
114
  return {
113
- status: 302,
115
+ status: req.statusCode ?? 302,
114
116
  location: req.url.toString(),
115
117
  };
116
118
  }
@@ -119,8 +121,9 @@ export async function main(data: MainData): Promise<{
119
121
  const ssrComponents = new SsrComponents();
120
122
  ssrComponents.addToContext(context);
121
123
 
122
- pluginsBeforeRender(new CrelteRequest(crelte, req, site));
123
- crelte.globals._updateSiteId(site.id);
124
+ const cr = new CrelteRequest(crelte, req);
125
+ pluginsBeforeRender(cr);
126
+ crelte.globals._updateSiteId(cr.site.id);
124
127
  // eslint-disable-next-line prefer-const
125
128
  let { html, head } = data.app.default.render(props, { context });
126
129
 
@@ -128,7 +131,7 @@ export async function main(data: MainData): Promise<{
128
131
  head += crelte.ssrCache._exportToHead();
129
132
 
130
133
  let htmlTemplate = data.serverData.htmlTemplate;
131
- htmlTemplate = htmlTemplate.replace('<!--page-lang-->', site.language);
134
+ htmlTemplate = htmlTemplate.replace('<!--page-lang-->', cr.site.language);
132
135
 
133
136
  const finalHtml = htmlTemplate
134
137
  .replace('</head>', head + '\n\t</head>')
@@ -205,12 +208,26 @@ export async function mainError(
205
208
  }
206
209
 
207
210
  // requires, GraphQl, SsrCache
208
- async function loadSites(builder: CrelteBuilder): Promise<SiteFromGraphQl[]> {
211
+ async function loadSites(
212
+ builder: CrelteBuilder,
213
+ serverData: ServerData,
214
+ ): Promise<SiteFromGraphQl[]> {
209
215
  if (!builder.graphQl) throw new Error();
210
216
 
211
217
  if ('CRAFT_SITES_CACHED' in globalThis) {
212
- // @ts-ignore
213
- return globalThis['CRAFT_SITES_CACHED'];
218
+ return (globalThis as any)['CRAFT_SITES_CACHED'];
219
+ }
220
+
221
+ if (import.meta.env.PROD && serverData.readSitesCache) {
222
+ try {
223
+ const sites =
224
+ (await serverData.readSitesCache()) as SiteFromGraphQl[];
225
+ // @ts-ignore
226
+ globalThis['CRAFT_SITES_CACHED'] = sites;
227
+ return sites;
228
+ } catch (_e: any) {
229
+ // ignore
230
+ }
214
231
  }
215
232
 
216
233
  const resp = (await builder.graphQl.query(
@@ -233,5 +250,8 @@ async function loadSites(builder: CrelteBuilder): Promise<SiteFromGraphQl[]> {
233
250
 
234
251
  // @ts-ignore
235
252
  globalThis['CRAFT_SITES_CACHED'] = resp.crelteSites;
253
+ if (import.meta.env.PROD && serverData.writeSitesCache) {
254
+ await serverData.writeSitesCache(resp.crelteSites);
255
+ }
236
256
  return resp.crelteSites;
237
257
  }
@@ -5,8 +5,8 @@ import { LoadData, callLoadData } from '../loadData/index.js';
5
5
  import { PluginCreator } from '../plugins/Plugins.js';
6
6
  import { LoadOptions } from '../routing/PageLoader.js';
7
7
 
8
- interface App<D, E, T> {
9
- loadGlobalData?: LoadData<D>;
8
+ interface App<E, T> {
9
+ loadGlobalData?: LoadData<null>;
10
10
 
11
11
  // todo: add a generic
12
12
  loadEntryData?: LoadData<any>;
@@ -60,7 +60,7 @@ export function getEntry(page: any): any {
60
60
 
61
61
  export async function loadFn<D, E, T>(
62
62
  cr: CrelteRequest,
63
- app: App<D, E, T>,
63
+ app: App<E, T>,
64
64
  entryQuery: GraphQlQuery,
65
65
  globalQuery?: GraphQlQuery,
66
66
  loadOpts?: LoadOptions,
@@ -75,7 +75,7 @@ export async function loadFn<D, E, T>(
75
75
  }
76
76
 
77
77
  if (app.loadGlobalData) {
78
- dataProm = callLoadData(app.loadGlobalData, cr) as any;
78
+ dataProm = callLoadData(app.loadGlobalData, cr, null) as any;
79
79
  }
80
80
 
81
81
  let globalProm: Promise<any> | null = null;
@@ -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 {