crelte 0.4.7 → 0.5.0-alpha.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 (110) hide show
  1. package/dist/Crelte.d.ts +7 -6
  2. package/dist/Crelte.d.ts.map +1 -1
  3. package/dist/Crelte.js +5 -13
  4. package/dist/CrelteRequest.d.ts +9 -0
  5. package/dist/CrelteRequest.d.ts.map +1 -1
  6. package/dist/CrelteRequest.js +16 -2
  7. package/dist/blocks/Blocks.svelte +2 -2
  8. package/dist/blocks/Blocks.svelte.d.ts +3 -19
  9. package/dist/blocks/Blocks.svelte.d.ts.map +1 -1
  10. package/dist/cookies/ClientCookies.d.ts +0 -1
  11. package/dist/cookies/ClientCookies.d.ts.map +1 -1
  12. package/dist/cookies/ClientCookies.js +0 -1
  13. package/dist/cookies/ServerCookies.d.ts +1 -2
  14. package/dist/cookies/ServerCookies.d.ts.map +1 -1
  15. package/dist/cookies/ServerCookies.js +2 -6
  16. package/dist/cookies/index.d.ts +0 -2
  17. package/dist/cookies/index.d.ts.map +1 -1
  18. package/dist/graphql/GraphQl.d.ts +2 -2
  19. package/dist/graphql/GraphQl.d.ts.map +1 -1
  20. package/dist/index.d.ts +9 -3
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +14 -6
  23. package/dist/init/InternalApp.d.ts +30 -0
  24. package/dist/init/InternalApp.d.ts.map +1 -0
  25. package/dist/init/InternalApp.js +71 -0
  26. package/dist/init/client.d.ts +0 -5
  27. package/dist/init/client.d.ts.map +1 -1
  28. package/dist/init/client.js +88 -75
  29. package/dist/init/crelte-vite-plugin.d.ts +5 -0
  30. package/dist/init/server.d.ts +0 -5
  31. package/dist/init/server.d.ts.map +1 -1
  32. package/dist/init/server.js +50 -20
  33. package/dist/init/shared.d.ts +7 -18
  34. package/dist/init/shared.d.ts.map +1 -1
  35. package/dist/init/shared.js +97 -154
  36. package/dist/init/svelteComponents.d.ts +3 -0
  37. package/dist/init/svelteComponents.d.ts.map +1 -0
  38. package/dist/init/svelteComponents.js +7 -0
  39. package/dist/loadData/Globals.d.ts +40 -33
  40. package/dist/loadData/Globals.d.ts.map +1 -1
  41. package/dist/loadData/Globals.js +99 -88
  42. package/dist/loadData/index.d.ts +3 -2
  43. package/dist/loadData/index.d.ts.map +1 -1
  44. package/dist/loadData/index.js +2 -0
  45. package/dist/plugins/Events.d.ts +11 -13
  46. package/dist/plugins/Events.d.ts.map +1 -1
  47. package/dist/plugins/Events.js +10 -3
  48. package/dist/routing/BaseRoute.d.ts +255 -0
  49. package/dist/routing/BaseRoute.d.ts.map +1 -0
  50. package/dist/routing/BaseRoute.js +349 -0
  51. package/dist/routing/BaseRouter.d.ts +210 -0
  52. package/dist/routing/BaseRouter.d.ts.map +1 -0
  53. package/dist/routing/BaseRouter.js +444 -0
  54. package/dist/routing/ClientRouter.d.ts +32 -0
  55. package/dist/routing/ClientRouter.d.ts.map +1 -0
  56. package/dist/routing/ClientRouter.js +259 -0
  57. package/dist/routing/LoadRunner.d.ts +39 -0
  58. package/dist/routing/LoadRunner.d.ts.map +1 -0
  59. package/dist/routing/{PageLoader.js → LoadRunner.js} +32 -20
  60. package/dist/routing/Request.d.ts +35 -3
  61. package/dist/routing/Request.d.ts.map +1 -1
  62. package/dist/routing/Request.js +64 -5
  63. package/dist/routing/Route.d.ts +24 -223
  64. package/dist/routing/Route.d.ts.map +1 -1
  65. package/dist/routing/Route.js +26 -315
  66. package/dist/routing/Router.d.ts +49 -73
  67. package/dist/routing/Router.d.ts.map +1 -1
  68. package/dist/routing/Router.js +85 -251
  69. package/dist/routing/ServerRouter.d.ts +23 -0
  70. package/dist/routing/ServerRouter.d.ts.map +1 -0
  71. package/dist/routing/ServerRouter.js +57 -0
  72. package/dist/routing/utils.d.ts +5 -0
  73. package/dist/routing/utils.d.ts.map +1 -1
  74. package/dist/routing/utils.js +39 -0
  75. package/dist/utils.d.ts +1 -0
  76. package/dist/utils.d.ts.map +1 -1
  77. package/dist/utils.js +3 -0
  78. package/package.json +6 -5
  79. package/src/Crelte.ts +12 -18
  80. package/src/CrelteRequest.ts +21 -2
  81. package/src/cookies/ClientCookies.ts +0 -2
  82. package/src/cookies/ServerCookies.ts +2 -7
  83. package/src/cookies/index.ts +0 -3
  84. package/src/graphql/GraphQl.ts +2 -1
  85. package/src/index.ts +17 -9
  86. package/src/init/InternalApp.ts +134 -0
  87. package/src/init/client.ts +104 -93
  88. package/src/init/crelte-vite-plugin.d.ts +5 -0
  89. package/src/init/server.ts +70 -35
  90. package/src/init/shared.ts +107 -227
  91. package/src/init/svelteComponents.ts +12 -0
  92. package/src/loadData/Globals.ts +121 -102
  93. package/src/loadData/index.ts +3 -2
  94. package/src/plugins/Events.ts +40 -42
  95. package/src/routing/BaseRoute.ts +422 -0
  96. package/src/routing/BaseRouter.ts +528 -0
  97. package/src/routing/ClientRouter.ts +329 -0
  98. package/src/routing/{PageLoader.ts → LoadRunner.ts} +43 -30
  99. package/src/routing/Request.ts +97 -12
  100. package/src/routing/Route.ts +56 -376
  101. package/src/routing/Router.ts +100 -359
  102. package/src/routing/ServerRouter.ts +78 -0
  103. package/src/routing/utils.ts +53 -0
  104. package/src/utils.ts +4 -0
  105. package/dist/routing/InnerRouter.d.ts +0 -113
  106. package/dist/routing/InnerRouter.d.ts.map +0 -1
  107. package/dist/routing/InnerRouter.js +0 -417
  108. package/dist/routing/PageLoader.d.ts +0 -36
  109. package/dist/routing/PageLoader.d.ts.map +0 -1
  110. package/src/routing/InnerRouter.ts +0 -498
@@ -1,94 +1,82 @@
1
- import EntryRouter from '../entry/EntryRouter.js';
1
+ import { isGraphQlQuery } from '../graphql/GraphQl.js';
2
2
  import { callLoadData } from '../loadData/index.js';
3
+ import { isPromise } from '../utils.js';
3
4
  export function setupPlugins(crelte, plugins) {
4
5
  for (const plugin of plugins) {
5
6
  const p = plugin(crelte);
6
7
  crelte.plugins.add(p);
7
8
  }
8
9
  }
9
- export function pluginsBeforeRender(cr) {
10
- cr.events.trigger('beforeRender', cr);
11
- }
12
- const ERROR_404_ENTRY = {
13
- sectionHandle: 'error',
14
- typeHandle: '404',
15
- };
16
- /**
17
- * Get the entry from the page
18
- *
19
- * entries should export sectionHandle and typeHandle
20
- *
21
- * products should alias productTypeHandle with typeHandle,
22
- * sectionHandle will be automatically set to product
23
- */
24
- function getEntry(page) {
25
- if (page?.entry)
26
- return { ...page.entry };
27
- if (page?.product)
28
- return {
29
- sectionHandle: 'product',
30
- ...page.product,
31
- };
32
- return null;
33
- }
34
- // todo it would be nice to call this only once per server start
35
- export async function prepareLoadFn(crelte, app, entryQuery, globalQuery) {
36
- const templateModules = prepareTemplates(app.templates ?? {});
37
- let entryRouter = null;
38
- if (app.entryRoutes) {
39
- entryRouter = new EntryRouter(crelte);
40
- await app.entryRoutes(entryRouter);
10
+ export function pluginsBeforeRequest(cr) {
11
+ const res = cr.events.trigger('beforeRequest', cr);
12
+ // if one of them is a promise we need to wait for it
13
+ if (res.some(isPromise)) {
14
+ return Promise.all(res).then();
41
15
  }
42
- return async (cr, loadOpts) => {
43
- return await loadFn(cr, app, templateModules, entryRouter, entryQuery, globalQuery, loadOpts);
44
- };
45
16
  }
46
- async function loadFn(cr, app, templateModules, entryRouter, entryQuery, globalQuery, loadOpts) {
47
- let dataProm = null;
48
- // @ts-ignore
49
- if (app.loadData) {
50
- throw new Error('loadData is ambigous, choose loadGlobalData or ' +
51
- 'loadEntryData depending on if you need access to entry or not?');
52
- }
53
- if (app.loadGlobalData) {
54
- dataProm = callLoadData(app.loadGlobalData, cr, null);
55
- }
17
+ export function pluginsBeforeRender(cr, route) {
18
+ cr.events.trigger('beforeRender', cr, route);
19
+ }
20
+ // This should be onRequest or handleRequest
21
+ //
22
+ // it should also handle the site redirect and stuff like that
23
+ // we should have a onRequest
24
+ export async function loadFn(cr, app, loadOpts) {
25
+ const isCanceled = () => !!loadOpts?.isCanceled();
26
+ // loadGlobalData phase
56
27
  let globalProm = null;
57
- if (globalQuery && !cr.globals._wasLoaded(cr.site.id)) {
28
+ if (app.loadGlobalData) {
29
+ // we need to set the globals as soon as loadGlobalData completes
30
+ // because other loadGlobalData functions might wait on the result
58
31
  globalProm = (async () => {
59
- const res = await cr.query(globalQuery, {
60
- siteId: cr.site.id,
61
- });
62
- // we need to do this sorcery here and can't wait until all
63
- // globals functions are done, because some global function
64
- // might want to use globals, and for that the function
65
- // getAsync exists on Globals
66
- cr.globals._setData(cr.site.id, res);
67
- return res;
32
+ // todo theoretically we could if the loadData is a an LoadObject
33
+ // assign each to the global as soon as we have it. Which might
34
+ // prevent some deadlocks but i don't think this will happen
35
+ // often
36
+ const globals = await callLoadData(app.loadGlobalData, cr, null);
37
+ if (!globals)
38
+ return globals;
39
+ if (typeof globals !== 'object') {
40
+ throw new Error('loadGlobalData needs to return an object or nothing');
41
+ }
42
+ for (const [k, v] of Object.entries(globals)) {
43
+ cr.globals.set(k, v);
44
+ }
68
45
  })();
69
46
  }
70
- const entryProm = queryEntry(cr, app, entryRouter, entryQuery);
47
+ // todo maybe each setting of the property on the request should be
48
+ // checked to be empty before doing it
49
+ const entryProm = (async () => {
50
+ let loadEntry = app.loadEntry;
51
+ if (isGraphQlQuery(loadEntry)) {
52
+ const entryQuery = loadEntry;
53
+ loadEntry = cr => queryEntry(cr, entryQuery);
54
+ }
55
+ let entry = await callLoadData(loadEntry, cr, null);
56
+ if (isCanceled())
57
+ return [];
58
+ cr.req.entry = entry;
59
+ await Promise.all(cr.events.trigger('afterLoadEntry', cr));
60
+ if (isCanceled())
61
+ return [];
62
+ entry = cr.req.entry;
63
+ const template = await app.loadTemplate(entry);
64
+ if (isCanceled())
65
+ return [];
66
+ cr.req.template = template;
67
+ return [entry, template];
68
+ })();
71
69
  const pluginsLoadGlobalData = cr.events.trigger('loadGlobalData', cr);
72
70
  // loading progress is at 20%
73
71
  loadOpts?.setProgress(0.2);
74
- const [data, global, entry] = await Promise.all([
75
- dataProm,
72
+ const [_global, [entry, template]] = await Promise.all([
76
73
  globalProm,
77
74
  entryProm,
78
75
  ...pluginsLoadGlobalData,
79
76
  ]);
80
- // global is only set if !wasLoaded but we need to store something
81
- // even if no globalQuery exists
82
- if (global || !cr.globals._wasLoaded(cr.site.id)) {
83
- cr.globals._setData(cr.site.id, global ?? {});
84
- }
85
- let template;
86
- if (app.templates) {
87
- template = await loadTemplate(templateModules, entry);
88
- }
89
- else {
90
- throw new Error('App must export some templates');
91
- }
77
+ if (isCanceled())
78
+ return;
79
+ cr.globals._globalsLoaded();
92
80
  // loading progress is at 60%
93
81
  loadOpts?.setProgress(0.6);
94
82
  const pluginsLoadData = cr.events.trigger('loadData', cr, entry);
@@ -105,92 +93,47 @@ async function loadFn(cr, app, templateModules, entryRouter, entryQuery, globalQ
105
93
  entryDataProm,
106
94
  ...pluginsLoadData,
107
95
  ]);
108
- // loading progress is at 100%
109
- loadOpts?.setProgress(1);
110
- return {
111
- ...data,
96
+ cr.req.loadedData = {
97
+ ...templateData,
112
98
  ...entryData,
113
- entry,
114
- template: template.default,
115
- templateData: templateData,
116
99
  };
100
+ // loading progress is at 100%
101
+ loadOpts?.setProgress(1);
117
102
  }
118
- function parseFilename(path) {
119
- // get filename with extension
120
- const slash = path.lastIndexOf('/');
121
- const filename = path.substring(slash + 1);
122
- const extPos = filename.lastIndexOf('.');
123
- const name = filename.substring(0, extPos);
124
- const ext = filename.substring(extPos + 1);
125
- return [name, ext];
126
- }
127
- async function queryEntry(cr, app, entryRouter, entryQuery) {
128
- let vars = null;
129
- if (cr.req.siteMatches()) {
130
- let uri = decodeURI(cr.req.uri);
131
- if (uri.startsWith('/'))
132
- uri = uri.substring(1);
133
- if (uri === '' || uri === '/')
134
- uri = '__home__';
135
- vars = {
136
- uri,
137
- siteId: cr.site.id,
138
- };
139
- }
140
- if (vars) {
141
- await Promise.all(cr.events.trigger('beforeQueryEntry', cr, vars));
142
- }
143
- // basic query function
144
- let loadFn = async (vars) => {
145
- if (entryRouter) {
146
- const entry = await entryRouter._handle(cr);
147
- if (entry)
148
- return entry;
149
- }
150
- if (vars) {
151
- const page = await cr.query(entryQuery, vars);
152
- return getEntry(page);
153
- }
154
- return null;
103
+ export async function queryEntry(cr, entryQuery) {
104
+ if (!cr.req.siteMatches())
105
+ throw new Error('to run the entryQuery the request needs to have a matching site');
106
+ let uri = decodeURI(cr.req.uri);
107
+ if (uri.startsWith('/'))
108
+ uri = uri.substring(1);
109
+ if (uri === '' || uri === '/')
110
+ uri = '__home__';
111
+ const vars = {
112
+ uri,
113
+ siteId: cr.site.id,
155
114
  };
156
- // check if a plugin wants to override the query
157
- const fns = cr.events.getListeners('queryEntry');
158
- for (const fn of fns) {
159
- const prevLoadFn = loadFn;
160
- loadFn = async (vars) => {
161
- return await fn(cr, vars, prevLoadFn);
162
- };
163
- }
164
- const entry = (await loadFn(vars)) ?? ERROR_404_ENTRY;
165
- await Promise.all(cr.events.trigger('afterQueryEntry', cr, entry));
166
- return entry;
167
- }
168
- function prepareTemplates(rawModules) {
169
- // parse modules
170
- return new Map(Object.entries(rawModules)
171
- .map(([path, mod]) => {
172
- const [name, _ext] = parseFilename(path);
173
- return [name, mod];
174
- })
175
- .filter(([name, _mod]) => !!name));
115
+ const page = await cr.query(entryQuery, vars);
116
+ return getEntry(page) ?? ERROR_404_ENTRY;
176
117
  }
177
- async function loadTemplate(modules, entry) {
178
- const entr = entry;
179
- const handle = `${entr.sectionHandle}-${entr.typeHandle}`;
180
- if (
181
- // @ts-ignore
182
- import.meta.env.DEV &&
183
- !modules.has(handle) &&
184
- !modules.has(entr.sectionHandle)) {
185
- console.error(`Template not found: <${handle}>, expecting file: ${handle}.svelte or ${entr.sectionHandle}.svelte`);
186
- }
187
- const loadMod = modules.get(handle) ??
188
- modules.get(entr.sectionHandle) ??
189
- modules.get('error-404');
190
- if (!loadMod)
191
- throw new Error('could not find error-404 template');
192
- if (typeof loadMod === 'function') {
193
- return await loadMod();
194
- }
195
- return loadMod;
118
+ const ERROR_404_ENTRY = {
119
+ sectionHandle: 'error',
120
+ typeHandle: '404',
121
+ };
122
+ /**
123
+ * Get the entry from the page
124
+ *
125
+ * entries should export sectionHandle and typeHandle
126
+ *
127
+ * products should alias productTypeHandle with typeHandle,
128
+ * sectionHandle will be automatically set to product
129
+ */
130
+ function getEntry(page) {
131
+ if (page?.entry)
132
+ return { ...page.entry };
133
+ if (page?.product)
134
+ return {
135
+ sectionHandle: 'product',
136
+ ...page.product,
137
+ };
138
+ return null;
196
139
  }
@@ -0,0 +1,3 @@
1
+ export declare function svelteMount(comp: any, options: any): any;
2
+ export declare function svelteRender(comp: any, options: any): any;
3
+ //# sourceMappingURL=svelteComponents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svelteComponents.d.ts","sourceRoot":"","sources":["../../src/init/svelteComponents.ts"],"names":[],"mappings":"AAKA,wBAAgB,WAAW,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,GAAG,GAAG,CAExD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,GAAG,GAAG,CAEzD"}
@@ -0,0 +1,7 @@
1
+ import { internalSvelteMount, internalSvelteRender, } from 'crelte-vite-plugin/svelteComponents.js';
2
+ export function svelteMount(comp, options) {
3
+ return internalSvelteMount(comp, options);
4
+ }
5
+ export function svelteRender(comp, options) {
6
+ return internalSvelteRender(comp, options);
7
+ }
@@ -1,11 +1,27 @@
1
- export type GlobalWaiters<T> = [(g: T | null) => void];
1
+ import { Readable, Writable } from 'crelte-std/stores';
2
+ export type GlobalWaiters<T> = ((g: T | null) => void)[];
3
+ /**
4
+ * Globals is sort of a queue
5
+ *
6
+ * each time a new request get's started
7
+ * a copy of globals is created which references some properties of the original one
8
+ *
9
+ * then if everything is loaded th original globals is "overriden" with the new one
10
+ * and we get a new state
11
+ */
2
12
  export default class Globals {
3
13
  private waiters;
4
- private data;
14
+ private newData;
5
15
  private stores;
6
- private currentSiteId;
7
- constructor();
8
- get<T = any>(name: string, siteId: number): T | null;
16
+ constructor(stores?: Map<string, Writable<any>>);
17
+ /**
18
+ * returns a globalValue
19
+ *
20
+ * ## Note
21
+ * This only works in loadData, in loadGlobalData this will
22
+ * throw an error. In that context you should use `.getAsync`
23
+ */
24
+ get<T = any>(name: string): T | null;
9
25
  /**
10
26
  * returns a store which contains a globalSet
11
27
  *
@@ -14,43 +30,34 @@ export default class Globals {
14
30
  * always return null. In that context you should use
15
31
  * `.getAsync`
16
32
  */
17
- getStore<T = any>(name: string): Global<T> | null;
33
+ getStore<T = any>(name: string): Readable<T> | null;
18
34
  /**
19
35
  * Get a store which contains a globalSet and wait until it is loaded
20
36
  *
21
37
  * ## Note
22
38
  * This is only useful in loadGlobalData in all other cases
23
- * you can use `.getGlobal` which does return a Promise
39
+ * you can use `.get` which does not return a Promise
24
40
  */
25
- getAsync<T = any>(name: string, siteId: number): Promise<T | null>;
26
- /** @hidden */
27
- _wasLoaded(siteId: number): boolean;
28
- /** @hidden */
29
- _setData(siteId: number, data: any): void;
30
- /** @hidden */
31
- _updateSiteId(siteId: number): void;
32
- }
33
- /**
34
- * A globalSet store
35
- */
36
- export declare class Global<T = any> {
37
- /** @hidden */
38
- private inner;
39
- constructor(name: string, data: T);
41
+ getAsync<T = any>(name: string): Promise<T | null> | T | null;
40
42
  /**
41
- * The function get's called once with the current value and then when the
42
- * values changes
43
- *
44
- * @return a function which should be called to unsubscribe
43
+ * can only be called in loadGlobalData contexts
44
+ */
45
+ set<T>(name: string, data: T): void;
46
+ /**
47
+ * @hidden
48
+ * call this before starting the loadGlobalData phase
49
+ */
50
+ _toRequest(): Globals;
51
+ /**
52
+ * @hidden
53
+ * call this after the loadGlobalData phase
45
54
  */
46
- subscribe(fn: (val: T) => void): () => void;
55
+ _globalsLoaded(): void;
47
56
  /**
48
- * The current value
57
+ * @hidden
58
+ * call this after the loadData phase once the CrelteRequest
59
+ * gets completed
49
60
  */
50
- get(): T;
51
- /** @hidden */
52
- _setSilent(value: T): void;
53
- /** @hidden */
54
- _notify(): void;
61
+ _syncToStores(): void;
55
62
  }
56
63
  //# sourceMappingURL=Globals.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Globals.d.ts","sourceRoot":"","sources":["../../src/loadData/Globals.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC;AAEvD,MAAM,CAAC,OAAO,OAAO,OAAO;IAG3B,OAAO,CAAC,OAAO,CAA+C;IAC9D,OAAO,CAAC,IAAI,CAAgC;IAC5C,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,aAAa,CAAgB;;IASrC,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAIpD;;;;;;;OAOG;IACH,QAAQ,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI;IAIjD;;;;;;OAMG;IACH,QAAQ,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAqBlE,cAAc;IACd,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAQnC,cAAc;IACd,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG;IAUlC,cAAc;IACd,aAAa,CAAC,MAAM,EAAE,MAAM;CAuB5B;AAED;;GAEG;AACH,qBAAa,MAAM,CAAC,CAAC,GAAG,GAAG;IAC1B,cAAc;IACd,OAAO,CAAC,KAAK,CAAc;gBAEf,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAiBjC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI;IAI3C;;OAEG;IACH,GAAG,IAAI,CAAC;IAIR,cAAc;IACd,UAAU,CAAC,KAAK,EAAE,CAAC;IAInB,cAAc;IACd,OAAO;CAGP"}
1
+ {"version":3,"file":"Globals.d.ts","sourceRoot":"","sources":["../../src/loadData/Globals.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEvD,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;AAEzD;;;;;;;;GAQG;AACH,MAAM,CAAC,OAAO,OAAO,OAAO;IAK3B,OAAO,CAAC,OAAO,CAAyC;IAIxD,OAAO,CAAC,OAAO,CAA0B;IAGzC,OAAO,CAAC,MAAM,CAA6B;gBAE/B,MAAM,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;IAM/C;;;;;;OAMG;IACH,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAmBpC;;;;;;;OAOG;IACH,QAAQ,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI;IAInD;;;;;;OAMG;IACH,QAAQ,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI;IAiB7D;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IA4B5B;;;OAGG;IACH,UAAU;IAQV;;;OAGG;IACH,cAAc;IAMd;;;;OAIG;IACH,aAAa;CAyBb"}
@@ -7,21 +7,48 @@ cr.getGlobal('emergency')
7
7
 
8
8
  */
9
9
  import { Writable } from 'crelte-std/stores';
10
+ /**
11
+ * Globals is sort of a queue
12
+ *
13
+ * each time a new request get's started
14
+ * a copy of globals is created which references some properties of the original one
15
+ *
16
+ * then if everything is loaded th original globals is "overriden" with the new one
17
+ * and we get a new state
18
+ */
10
19
  export default class Globals {
11
20
  // while the globals are not loaded if somebody calls
12
21
  // getAsync then we need to store the waiters
22
+ // this get's created as soon as a request was started
23
+ // and get's deleted as soon as all globals are loaded
13
24
  waiters;
14
- data;
25
+ // this get's created as soon as a request was started
26
+ // and deleted once they are synced to the stores
27
+ newData;
28
+ // contains the current active globals
15
29
  stores;
16
- currentSiteId;
17
- constructor() {
18
- this.waiters = new Map();
19
- this.data = new Map();
20
- this.stores = new Map();
21
- this.currentSiteId = null;
30
+ constructor(stores) {
31
+ this.waiters = null;
32
+ this.newData = null;
33
+ this.stores = stores ?? new Map();
22
34
  }
23
- get(name, siteId) {
24
- return this.data.get(siteId)?.get(name) ?? null;
35
+ /**
36
+ * returns a globalValue
37
+ *
38
+ * ## Note
39
+ * This only works in loadData, in loadGlobalData this will
40
+ * throw an error. In that context you should use `.getAsync`
41
+ */
42
+ get(name) {
43
+ if (this.waiters)
44
+ throw new Error('calling get in loadGlobalData will not work. call getAsync');
45
+ if (!this.newData) {
46
+ throw new Error('calling get outside of a loadData is forbidden. use getStore');
47
+ // todo do we wan't to allow this?
48
+ // isn't it just a footgun?
49
+ // return this.getStore(name)?.get() ?? null;
50
+ }
51
+ return this.newData.get(name) ?? null;
25
52
  }
26
53
  /**
27
54
  * returns a store which contains a globalSet
@@ -32,78 +59,35 @@ export default class Globals {
32
59
  * `.getAsync`
33
60
  */
34
61
  getStore(name) {
35
- return this.stores.get(name) ?? null;
62
+ return this.stores.get(name)?.readonly() ?? null;
36
63
  }
37
64
  /**
38
65
  * Get a store which contains a globalSet and wait until it is loaded
39
66
  *
40
67
  * ## Note
41
68
  * This is only useful in loadGlobalData in all other cases
42
- * you can use `.getGlobal` which does return a Promise
69
+ * you can use `.get` which does not return a Promise
43
70
  */
44
- getAsync(name, siteId) {
45
- if (this._wasLoaded(siteId))
46
- return Promise.resolve(this.get(name, siteId));
47
- let listeners = this.waiters.get(siteId);
71
+ getAsync(name) {
72
+ if (this.newData)
73
+ return this.newData.get(name) ?? null;
74
+ if (!this.waiters)
75
+ throw new Error('calling getAsync in non loadGlobalData contexts is pointless. Use getStore instead');
76
+ let listeners = this.waiters.get(name);
48
77
  if (!listeners) {
49
- listeners = new Map();
50
- this.waiters.set(siteId, listeners);
78
+ listeners = [];
79
+ this.waiters.set(name, listeners);
51
80
  }
52
- let waiter = listeners.get(name);
53
- if (!waiter) {
54
- waiter = [];
55
- listeners.set(name, waiter);
56
- }
57
- return new Promise(resolve => {
58
- waiter.push(resolve);
59
- });
60
- }
61
- /** @hidden */
62
- _wasLoaded(siteId) {
63
- return this.data.has(siteId);
64
- }
65
- // data is the data from the global graphql
66
- // so it contains some keys and data which should be parsed
67
- // and created a store for each key
68
- // do not call this if _wasLoaded returns true with the same siteId
69
- /** @hidden */
70
- _setData(siteId, data) {
71
- const map = new Map(Object.entries(data));
72
- this.data.set(siteId, map);
73
- this.waiters.get(siteId)?.forEach((waiters, key) => {
74
- waiters.forEach(waiter => waiter(map.get(key)));
75
- });
76
- this.waiters.delete(siteId);
77
- }
78
- /** @hidden */
79
- _updateSiteId(siteId) {
80
- if (this.currentSiteId === siteId)
81
- return;
82
- const data = this.data.get(siteId) ?? new Map();
83
- // we set all global data to null via setSilent
84
- // then set them all with the new data
85
- // and update all of them
86
- this.stores.forEach(global => global._setSilent(null));
87
- data.forEach((value, key) => {
88
- let global = this.stores.get(key);
89
- if (global) {
90
- global._setSilent(value);
91
- }
92
- else {
93
- global = new Global(key, value);
94
- this.stores.set(key, global);
95
- }
96
- });
97
- this.stores.forEach(global => global._notify());
81
+ return new Promise(resolve => listeners.push(resolve));
98
82
  }
99
- }
100
- /**
101
- * A globalSet store
102
- */
103
- export class Global {
104
- /** @hidden */
105
- inner;
106
- constructor(name, data) {
83
+ /**
84
+ * can only be called in loadGlobalData contexts
85
+ */
86
+ set(name, data) {
87
+ if (!this.newData) {
88
+ // this is not strictly necessary but
89
+ throw new Error('can only be called in loadGlobalData contexts');
90
+ }
107
91
  // todo remove in v1.0
108
92
  // In v0.2, we queried the global data for all sites.
109
93
  // We now check if the siteId is present and notify the user to remove it.
@@ -112,29 +96,56 @@ export class Global {
112
96
  throw new Error(`The global query ${name} should not include the siteId` +
113
97
  ` property. Instead, use the siteId as a parameter.`);
114
98
  }
115
- this.inner = new Writable(data);
99
+ this.newData?.set(name, data);
100
+ const listeners = this.waiters?.get(name);
101
+ if (listeners) {
102
+ this.waiters.delete(name);
103
+ listeners.forEach(fn => fn(data));
104
+ }
116
105
  }
117
106
  /**
118
- * The function get's called once with the current value and then when the
119
- * values changes
120
- *
121
- * @return a function which should be called to unsubscribe
107
+ * @hidden
108
+ * call this before starting the loadGlobalData phase
122
109
  */
123
- subscribe(fn) {
124
- return this.inner.subscribe(fn);
110
+ _toRequest() {
111
+ const nGlobals = new Globals(this.stores);
112
+ nGlobals.waiters = new Map();
113
+ nGlobals.newData = new Map();
114
+ return nGlobals;
125
115
  }
126
116
  /**
127
- * The current value
117
+ * @hidden
118
+ * call this after the loadGlobalData phase
128
119
  */
129
- get() {
130
- return this.inner.get();
131
- }
132
- /** @hidden */
133
- _setSilent(value) {
134
- this.inner.setSilent(value);
120
+ _globalsLoaded() {
121
+ // todo should we check if there are still waiters?
122
+ // theoretically this should never happen
123
+ this.waiters = null;
135
124
  }
136
- /** @hidden */
137
- _notify() {
138
- this.inner.notify();
125
+ /**
126
+ * @hidden
127
+ * call this after the loadData phase once the CrelteRequest
128
+ * gets completed
129
+ */
130
+ _syncToStores() {
131
+ const setToNull = new Set(this.stores.keys());
132
+ for (const [name, data] of this.newData.entries()) {
133
+ setToNull.delete(name);
134
+ const store = this.stores.get(name);
135
+ if (store) {
136
+ // todo should we do this check always?
137
+ if (store.get() !== data)
138
+ store.set(data);
139
+ }
140
+ else {
141
+ this.stores.set(name, new Writable(data));
142
+ }
143
+ }
144
+ for (const name of setToNull) {
145
+ console.warn(`global ${name} was not modified setting to null and removing it`);
146
+ this.stores.get(name).set(null);
147
+ this.stores.delete(name);
148
+ }
149
+ this.newData = null;
139
150
  }
140
151
  }
@@ -1,8 +1,7 @@
1
1
  import CrelteRequest from '../CrelteRequest.js';
2
2
  import { type GraphQlQuery } from '../graphql/GraphQl.js';
3
3
  import type Globals from './Globals.js';
4
- import type { Global } from './Globals.js';
5
- export type { Globals, Global };
4
+ export type { Globals };
6
5
  export interface LoadDataFn<A1 = any> {
7
6
  (cr: CrelteRequest, entryOrBlock: A1, ...args: any[]): Promise<any> | any;
8
7
  }
@@ -80,6 +79,8 @@ export declare function callLoadData<A1 = any>(ld: LoadData<A1>, cr: CrelteReque
80
79
  /**
81
80
  * Spread the data of two loadData functions.
82
81
  *
82
+ * Prefer to use the array syntax.
83
+ *
83
84
  * ## Example
84
85
  * ```
85
86
  * export const loadData = mergeLoadData(
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/loadData/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAEhC,MAAM,WAAW,UAAU,CAAC,EAAE,GAAG,GAAG;IACnC,CAAC,EAAE,EAAE,aAAa,EAAE,YAAY,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;CAC1E;AAED,MAAM,WAAW,WAAW,CAAC,EAAE,GAAG,GAAG;IACpC,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;CAC5B;AAGD,MAAM,WAAW,aAAa,CAAC,EAAE,GAAG,GAAG,CAAE,SAAQ,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;CAAG;AAKvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AACH,MAAM,MAAM,QAAQ,CAAC,EAAE,GAAG,GAAG,IAC1B,UAAU,CAAC,EAAE,CAAC,GACd,YAAY,GACZ,WAAW,CAAC,EAAE,CAAC,GACf,aAAa,CAAC,EAAE,CAAC,GACjB,MAAM,GACN,MAAM,GACN,IAAI,GACJ,SAAS,CAAC;AAOb,wBAAsB,YAAY,CAAC,EAAE,GAAG,GAAG,EAC1C,EAAE,EAAE,QAAQ,CAAC,EAAE,CAAC,EAChB,EAAE,EAAE,aAAa,EACjB,IAAI,EAAE,EAAE,EACR,GAAG,IAAI,EAAE,GAAG,EAAE,GACZ,OAAO,CAAC,GAAG,CAAC,CA6Bd;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,EAAE,GAAG,GAAG,EACrC,GAAG,GAAG,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,GACpB,UAAU,CAAC,EAAE,CAAC,CAUhB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/loadData/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAExC,YAAY,EAAE,OAAO,EAAE,CAAC;AAExB,MAAM,WAAW,UAAU,CAAC,EAAE,GAAG,GAAG;IACnC,CAAC,EAAE,EAAE,aAAa,EAAE,YAAY,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;CAC1E;AAED,MAAM,WAAW,WAAW,CAAC,EAAE,GAAG,GAAG;IACpC,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;CAC5B;AAGD,MAAM,WAAW,aAAa,CAAC,EAAE,GAAG,GAAG,CAAE,SAAQ,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;CAAG;AAKvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AACH,MAAM,MAAM,QAAQ,CAAC,EAAE,GAAG,GAAG,IAC1B,UAAU,CAAC,EAAE,CAAC,GACd,YAAY,GACZ,WAAW,CAAC,EAAE,CAAC,GACf,aAAa,CAAC,EAAE,CAAC,GACjB,MAAM,GACN,MAAM,GACN,IAAI,GACJ,SAAS,CAAC;AAOb,wBAAsB,YAAY,CAAC,EAAE,GAAG,GAAG,EAC1C,EAAE,EAAE,QAAQ,CAAC,EAAE,CAAC,EAChB,EAAE,EAAE,aAAa,EACjB,IAAI,EAAE,EAAE,EACR,GAAG,IAAI,EAAE,GAAG,EAAE,GACZ,OAAO,CAAC,GAAG,CAAC,CA6Bd;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,EAAE,GAAG,GAAG,EACrC,GAAG,GAAG,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,GACpB,UAAU,CAAC,EAAE,CAAC,CAUhB"}