crelte 0.5.10 → 0.5.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bodyClass/BodyClass.d.ts +39 -0
- package/dist/bodyClass/BodyClass.d.ts.map +1 -0
- package/dist/bodyClass/BodyClass.js +51 -0
- package/dist/bodyClass/ClientBodyClass.d.ts +12 -0
- package/dist/bodyClass/ClientBodyClass.d.ts.map +1 -0
- package/dist/bodyClass/ClientBodyClass.js +57 -0
- package/dist/bodyClass/ServerBodyClass.d.ts +12 -0
- package/dist/bodyClass/ServerBodyClass.d.ts.map +1 -0
- package/dist/bodyClass/ServerBodyClass.js +47 -0
- package/dist/bodyClass/index.d.ts +2 -0
- package/dist/bodyClass/index.d.ts.map +1 -0
- package/dist/bodyClass/index.js +1 -0
- package/dist/cookies/ClientCookies.d.ts +8 -3
- package/dist/cookies/ClientCookies.d.ts.map +1 -1
- package/dist/cookies/ClientCookies.js +31 -7
- package/dist/cookies/Cookies.d.ts +42 -0
- package/dist/cookies/Cookies.d.ts.map +1 -0
- package/dist/cookies/Cookies.js +44 -0
- package/dist/cookies/ServerCookies.d.ts +3 -2
- package/dist/cookies/ServerCookies.d.ts.map +1 -1
- package/dist/cookies/ServerCookies.js +6 -4
- package/dist/cookies/index.d.ts +1 -25
- package/dist/cookies/index.d.ts.map +1 -1
- package/dist/cookies/index.js +1 -1
- package/dist/crelte.d.ts +7 -1
- package/dist/crelte.d.ts.map +1 -1
- package/dist/crelte.js +2 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/init/client.d.ts +1 -8
- package/dist/init/client.d.ts.map +1 -1
- package/dist/init/client.js +26 -24
- package/dist/init/server.d.ts.map +1 -1
- package/dist/init/server.js +12 -4
- package/dist/init/shared.d.ts +1 -0
- package/dist/init/shared.d.ts.map +1 -1
- package/dist/init/shared.js +16 -5
- package/dist/loadData/Globals.d.ts.map +1 -1
- package/dist/node/index.js +1 -1
- package/dist/plugins/Events.d.ts +12 -7
- package/dist/plugins/Events.d.ts.map +1 -1
- package/dist/plugins/Plugins.d.ts +36 -1
- package/dist/plugins/Plugins.d.ts.map +1 -1
- package/dist/plugins/Plugins.js +32 -0
- package/dist/queries/Queries.d.ts +30 -5
- package/dist/queries/Queries.d.ts.map +1 -1
- package/dist/queries/Queries.js +19 -2
- package/dist/queries/gql.d.ts +2 -2
- package/dist/queries/gql.d.ts.map +1 -1
- package/dist/queries/index.d.ts +47 -2
- package/dist/queries/index.d.ts.map +1 -1
- package/dist/queries/index.js +2 -2
- package/dist/queries/vars.d.ts +2 -0
- package/dist/queries/vars.d.ts.map +1 -1
- package/dist/queries/vars.js +10 -0
- package/dist/routing/route/Request.d.ts +1 -1
- package/dist/routing/route/Request.d.ts.map +1 -1
- package/dist/routing/route/Request.js +7 -3
- package/dist/routing/router/BaseRouter.d.ts +2 -1
- package/dist/routing/router/BaseRouter.d.ts.map +1 -1
- package/dist/routing/router/BaseRouter.js +4 -2
- package/dist/routing/router/ClientRouter.d.ts.map +1 -1
- package/dist/routing/router/ClientRouter.js +21 -15
- package/dist/routing/router/Router.d.ts +2 -1
- package/dist/routing/router/Router.d.ts.map +1 -1
- package/dist/routing/router/Router.js +10 -13
- package/dist/routing/utils.d.ts +1 -0
- package/dist/routing/utils.d.ts.map +1 -1
- package/dist/routing/utils.js +1 -1
- package/dist/server/CrelteServer.d.ts +1 -0
- package/dist/server/CrelteServer.d.ts.map +1 -1
- package/dist/server/CrelteServer.js +5 -2
- package/dist/server/ServerRouter.d.ts.map +1 -1
- package/dist/server/ServerRouter.js +17 -7
- package/dist/server/queries/QueryGqlRoute.d.ts +28 -0
- package/dist/server/queries/QueryGqlRoute.d.ts.map +1 -0
- package/dist/server/queries/QueryGqlRoute.js +194 -0
- package/dist/server/queries/QueryHandleRoute.d.ts +12 -0
- package/dist/server/queries/QueryHandleRoute.d.ts.map +1 -0
- package/dist/server/queries/QueryHandleRoute.js +24 -0
- package/dist/server/queries/queries.d.ts.map +1 -1
- package/dist/server/queries/queries.js +42 -19
- package/dist/server/queries/routes.d.ts +7 -30
- package/dist/server/queries/routes.d.ts.map +1 -1
- package/dist/server/queries/routes.js +13 -199
- package/dist/std/stores/StagedWritable.d.ts +48 -0
- package/dist/std/stores/StagedWritable.d.ts.map +1 -0
- package/dist/std/stores/StagedWritable.js +84 -0
- package/dist/std/stores/index.d.ts +2 -1
- package/dist/std/stores/index.d.ts.map +1 -1
- package/dist/std/stores/index.js +2 -1
- package/dist/std/sync/Barrier.js +1 -1
- package/dist/utils.d.ts +9 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +11 -0
- package/package.json +5 -1
- package/src/bodyClass/BodyClass.ts +72 -0
- package/src/bodyClass/ClientBodyClass.ts +62 -0
- package/src/bodyClass/ServerBodyClass.ts +65 -0
- package/src/bodyClass/index.ts +1 -0
- package/src/cookies/ClientCookies.ts +41 -10
- package/src/cookies/Cookies.ts +70 -0
- package/src/cookies/ServerCookies.ts +9 -6
- package/src/cookies/index.ts +5 -29
- package/src/crelte.ts +9 -0
- package/src/index.ts +15 -1
- package/src/init/client.ts +29 -24
- package/src/init/server.ts +12 -4
- package/src/init/shared.ts +18 -6
- package/src/loadData/Globals.ts +1 -1
- package/src/node/index.ts +1 -1
- package/src/plugins/Events.ts +22 -7
- package/src/plugins/Plugins.ts +66 -1
- package/src/queries/Queries.ts +47 -14
- package/src/queries/gql.ts +2 -2
- package/src/queries/index.ts +71 -0
- package/src/queries/vars.ts +13 -0
- package/src/routing/route/Request.ts +11 -4
- package/src/routing/router/BaseRouter.ts +4 -2
- package/src/routing/router/ClientRouter.ts +26 -18
- package/src/routing/router/Router.ts +10 -11
- package/src/routing/utils.ts +1 -1
- package/src/server/CrelteServer.ts +4 -2
- package/src/server/ServerRouter.ts +18 -7
- package/src/server/queries/QueryGqlRoute.ts +224 -0
- package/src/server/queries/QueryHandleRoute.ts +37 -0
- package/src/server/queries/queries.ts +57 -21
- package/src/server/queries/routes.ts +25 -229
- package/src/std/stores/StagedWritable.ts +96 -0
- package/src/std/stores/index.ts +2 -1
- package/src/std/sync/Barrier.ts +1 -1
- package/src/utils.ts +15 -0
package/src/init/client.ts
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
loadFn,
|
|
4
4
|
newQueries,
|
|
5
5
|
onNewCrelteRequest,
|
|
6
|
+
pluginsAfterRender,
|
|
6
7
|
pluginsBeforeRender,
|
|
7
8
|
pluginsBeforeRequest,
|
|
8
9
|
setupPlugins,
|
|
@@ -19,6 +20,9 @@ import Plugins from '../plugins/Plugins.js';
|
|
|
19
20
|
import Events from '../plugins/Events.js';
|
|
20
21
|
import Globals from '../loadData/Globals.js';
|
|
21
22
|
import { Writable } from '../std/stores/index.js';
|
|
23
|
+
import ClientBodyClass from '../bodyClass/ClientBodyClass.js';
|
|
24
|
+
import { BodyClass } from '../bodyClass/index.js';
|
|
25
|
+
import { Cookies } from '../cookies/index.js';
|
|
22
26
|
|
|
23
27
|
/**
|
|
24
28
|
* The main function to start the client side rendering
|
|
@@ -37,16 +41,9 @@ export type MainData = {
|
|
|
37
41
|
* ```js
|
|
38
42
|
* import * as app from './App.svelte';
|
|
39
43
|
* import * as errorPage from './Error.svelte';
|
|
40
|
-
* import entryQuery from './queries/entry.graphql';
|
|
41
|
-
* import globalQuery from './queries/global.graphql';
|
|
42
44
|
* import { main } from 'crelte/client';
|
|
43
45
|
*
|
|
44
|
-
* main({
|
|
45
|
-
* app,
|
|
46
|
-
* errorPage,
|
|
47
|
-
* entryQuery,
|
|
48
|
-
* globalQuery,
|
|
49
|
-
* });
|
|
46
|
+
* main({ app, errorPage });
|
|
50
47
|
* ```
|
|
51
48
|
*/
|
|
52
49
|
export async function main(data: MainData) {
|
|
@@ -81,7 +78,6 @@ export async function main(data: MainData) {
|
|
|
81
78
|
});
|
|
82
79
|
|
|
83
80
|
const queries = newQueries(ssrCache, router.route.readonly(), config);
|
|
84
|
-
const cookies = new ClientCookies();
|
|
85
81
|
|
|
86
82
|
const crelte = newCrelte({
|
|
87
83
|
config,
|
|
@@ -91,7 +87,8 @@ export async function main(data: MainData) {
|
|
|
91
87
|
globals: new Globals(),
|
|
92
88
|
router: new Router(router),
|
|
93
89
|
queries,
|
|
94
|
-
cookies,
|
|
90
|
+
cookies: new Cookies(new ClientCookies()),
|
|
91
|
+
bodyClass: new BodyClass(new ClientBodyClass()),
|
|
95
92
|
});
|
|
96
93
|
|
|
97
94
|
const app = new InternalApp(data.app);
|
|
@@ -108,22 +105,22 @@ export async function main(data: MainData) {
|
|
|
108
105
|
|
|
109
106
|
// render Space
|
|
110
107
|
|
|
111
|
-
let
|
|
112
|
-
let routeProp: Writable<Route>;
|
|
108
|
+
let routeProp: Writable<Route> | null = null;
|
|
113
109
|
const renderApp = (route: Route) => {
|
|
114
|
-
if (
|
|
115
|
-
routeProp
|
|
110
|
+
if (routeProp) {
|
|
111
|
+
routeProp.set(route);
|
|
116
112
|
return;
|
|
117
113
|
}
|
|
118
114
|
|
|
119
115
|
routeProp = new Writable(route);
|
|
120
|
-
|
|
116
|
+
svelteMount(data.app.default, {
|
|
121
117
|
target: document.body,
|
|
122
118
|
props: { route: routeProp },
|
|
123
119
|
context: new Map([['crelte', crelte]]),
|
|
124
120
|
intro: config.playIntro,
|
|
125
121
|
});
|
|
126
122
|
};
|
|
123
|
+
const appMounted = () => !!routeProp;
|
|
127
124
|
|
|
128
125
|
router.onError = (e, req) => {
|
|
129
126
|
console.error('routing failed:', e, 'reloading trying to fix it');
|
|
@@ -133,12 +130,12 @@ export async function main(data: MainData) {
|
|
|
133
130
|
};
|
|
134
131
|
|
|
135
132
|
router.onRender = async (cr, readyForRoute, domUpdated) => {
|
|
136
|
-
if (
|
|
133
|
+
if (appMounted() && cr.req.disableLoadData) {
|
|
137
134
|
// if the app is already rendered and entry did not change
|
|
138
|
-
// we just wan't to run domUpdated because we don't
|
|
135
|
+
// we just wan't to run domUpdated because we don't want to update anything
|
|
139
136
|
|
|
140
137
|
const route = readyForRoute();
|
|
141
|
-
cr.router.
|
|
138
|
+
cr.router.z_requestCompleted();
|
|
142
139
|
// globals should not be run because they will be empty
|
|
143
140
|
// since nobody called loadGlobalData (todo maybe globals should also,
|
|
144
141
|
// know if it accepts updates)
|
|
@@ -147,6 +144,7 @@ export async function main(data: MainData) {
|
|
|
147
144
|
await tick();
|
|
148
145
|
|
|
149
146
|
domUpdated(cr, route);
|
|
147
|
+
pluginsAfterRender(cr, route);
|
|
150
148
|
|
|
151
149
|
return route;
|
|
152
150
|
}
|
|
@@ -155,10 +153,16 @@ export async function main(data: MainData) {
|
|
|
155
153
|
|
|
156
154
|
let render = async () => {
|
|
157
155
|
const route = readyForRoute();
|
|
158
|
-
cr.router.
|
|
159
|
-
|
|
160
|
-
// we
|
|
161
|
-
|
|
156
|
+
cr.router.z_requestCompleted();
|
|
157
|
+
// this is only important on the first render
|
|
158
|
+
// else we will catch an earlier branch in onRender
|
|
159
|
+
if (route.entryChanged) {
|
|
160
|
+
cr.globals.z_syncToStores();
|
|
161
|
+
pluginsBeforeRender(cr, route);
|
|
162
|
+
cr.cookies.z_render();
|
|
163
|
+
cr.bodyClass.z_render();
|
|
164
|
+
}
|
|
165
|
+
|
|
162
166
|
renderApp(route);
|
|
163
167
|
|
|
164
168
|
await tick();
|
|
@@ -170,6 +174,7 @@ export async function main(data: MainData) {
|
|
|
170
174
|
}
|
|
171
175
|
|
|
172
176
|
domUpdated(cr, route);
|
|
177
|
+
pluginsAfterRender(cr, route);
|
|
173
178
|
|
|
174
179
|
return route;
|
|
175
180
|
};
|
|
@@ -177,7 +182,7 @@ export async function main(data: MainData) {
|
|
|
177
182
|
// render with view Transition if enabled and not in hydration
|
|
178
183
|
if (
|
|
179
184
|
config.viewTransition &&
|
|
180
|
-
|
|
185
|
+
appMounted() &&
|
|
181
186
|
(document as any).startViewTransition
|
|
182
187
|
) {
|
|
183
188
|
const prevRender = render;
|
|
@@ -218,8 +223,8 @@ function handleLoadError(e: any) {
|
|
|
218
223
|
|
|
219
224
|
// Messages in different languages
|
|
220
225
|
const messages: Record<string, string> = {
|
|
221
|
-
en: 'An error has occurred. Please reload the page or try again later.',
|
|
222
226
|
de: 'Leider ist ein Fehler aufgetreten. Laden Sie die Seite neu, oder versuchen Sie es später noch mal.',
|
|
227
|
+
en: 'An error has occurred. Please reload the page or try again later.',
|
|
223
228
|
fr: 'Une erreur s’est produite. Veuillez recharger la page ou réessayer plus tard.',
|
|
224
229
|
it: 'Si è verificato un errore. Ricarica la pagina o riprova più tardi.',
|
|
225
230
|
nl: 'Er is een fout opgetreden. Herlaad de pagina of probeer het later opnieuw.',
|
package/src/init/server.ts
CHANGED
|
@@ -23,6 +23,9 @@ import {
|
|
|
23
23
|
RenderRequest,
|
|
24
24
|
RenderResponse,
|
|
25
25
|
} from '../server/shared.js';
|
|
26
|
+
import ServerBodyClass from '../bodyClass/ServerBodyClass.js';
|
|
27
|
+
import BodyClass from '../bodyClass/BodyClass.js';
|
|
28
|
+
import { Cookies } from '../cookies/index.js';
|
|
26
29
|
|
|
27
30
|
export { type RenderRequest, type RenderResponse } from '../server/shared.js';
|
|
28
31
|
|
|
@@ -75,6 +78,7 @@ export async function main(data: MainData): Promise<RenderResponse> {
|
|
|
75
78
|
ssrCache.set('FRONTEND_URL', data.serverData.frontend);
|
|
76
79
|
|
|
77
80
|
const cookies = new ServerCookies(data.serverData.headers);
|
|
81
|
+
const bodyClass = new ServerBodyClass();
|
|
78
82
|
|
|
79
83
|
ssrCache.set('crelteSites', data.serverData.sites);
|
|
80
84
|
const router = new ServerRouter(
|
|
@@ -93,7 +97,8 @@ export async function main(data: MainData): Promise<RenderResponse> {
|
|
|
93
97
|
globals: new Globals(),
|
|
94
98
|
router: new Router(router),
|
|
95
99
|
queries,
|
|
96
|
-
cookies,
|
|
100
|
+
cookies: new Cookies(cookies),
|
|
101
|
+
bodyClass: new BodyClass(bodyClass),
|
|
97
102
|
});
|
|
98
103
|
|
|
99
104
|
const app = new InternalApp(data.app);
|
|
@@ -108,9 +113,11 @@ export async function main(data: MainData): Promise<RenderResponse> {
|
|
|
108
113
|
|
|
109
114
|
router.onRender = (cr, readyForRoute, _domUpdated) => {
|
|
110
115
|
const route = readyForRoute();
|
|
111
|
-
cr.router.
|
|
116
|
+
cr.router.z_requestCompleted();
|
|
112
117
|
cr.globals.z_syncToStores();
|
|
113
118
|
pluginsBeforeRender(cr, route);
|
|
119
|
+
cr.cookies.z_render();
|
|
120
|
+
cr.bodyClass.z_render();
|
|
114
121
|
|
|
115
122
|
return route;
|
|
116
123
|
};
|
|
@@ -121,7 +128,7 @@ export async function main(data: MainData): Promise<RenderResponse> {
|
|
|
121
128
|
// if redirect
|
|
122
129
|
if (!route) {
|
|
123
130
|
const headers = new Headers();
|
|
124
|
-
|
|
131
|
+
cookies._populateHeaders(headers);
|
|
125
132
|
|
|
126
133
|
return {
|
|
127
134
|
status: req.statusCode ?? 302,
|
|
@@ -153,6 +160,7 @@ export async function main(data: MainData): Promise<RenderResponse> {
|
|
|
153
160
|
'<!--page-lang-->',
|
|
154
161
|
route.site.language,
|
|
155
162
|
);
|
|
163
|
+
htmlTemplate = bodyClass.z_processHtmlTemplate(htmlTemplate);
|
|
156
164
|
|
|
157
165
|
const finalHtml = htmlTemplate
|
|
158
166
|
.replace('</head>', head + '\n\t</head>')
|
|
@@ -161,7 +169,7 @@ export async function main(data: MainData): Promise<RenderResponse> {
|
|
|
161
169
|
const entry = route.entry;
|
|
162
170
|
|
|
163
171
|
const headers = new Headers();
|
|
164
|
-
|
|
172
|
+
cookies._populateHeaders(headers);
|
|
165
173
|
|
|
166
174
|
return {
|
|
167
175
|
status:
|
package/src/init/shared.ts
CHANGED
|
@@ -32,6 +32,11 @@ export function pluginsBeforeRequest(cr: CrelteRequest): Promise<void> | void {
|
|
|
32
32
|
|
|
33
33
|
export function pluginsBeforeRender(cr: CrelteRequest, route: Route): void {
|
|
34
34
|
cr.events.trigger('beforeRender', cr, route);
|
|
35
|
+
cr.plugins.z_render(cr, route);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function pluginsAfterRender(cr: CrelteRequest, route: Route): void {
|
|
39
|
+
cr.events.trigger('afterRender', cr, route);
|
|
35
40
|
}
|
|
36
41
|
|
|
37
42
|
export function newQueries(
|
|
@@ -64,12 +69,15 @@ export function onNewCrelteRequest(
|
|
|
64
69
|
...crelte,
|
|
65
70
|
router: crelte.router.z_toRequest(req),
|
|
66
71
|
queries: crelte.queries.z_toRequest(req),
|
|
72
|
+
plugins: crelte.plugins.z_toRequest(req),
|
|
67
73
|
globals: crelte.globals.z_toRequest(),
|
|
74
|
+
cookies: crelte.cookies.z_toRequest(),
|
|
75
|
+
bodyClass: crelte.bodyClass.z_toRequest(),
|
|
68
76
|
};
|
|
69
77
|
return crelteToRequest(nCrelte, req);
|
|
70
78
|
}
|
|
71
79
|
|
|
72
|
-
async function
|
|
80
|
+
async function eventsLoadEntry(cr: CrelteRequest): Promise<Entry | null> {
|
|
73
81
|
const listeners = cr.events.getListeners('loadEntry');
|
|
74
82
|
|
|
75
83
|
for (const loadEntry of listeners) {
|
|
@@ -123,7 +131,7 @@ export async function loadFn(
|
|
|
123
131
|
// checked to be empty before doing it
|
|
124
132
|
const entryProm = (async () => {
|
|
125
133
|
// first let's try to call the plugin loadEntry
|
|
126
|
-
let entry = await
|
|
134
|
+
let entry = await eventsLoadEntry(cr);
|
|
127
135
|
if (isCanceled()) return [];
|
|
128
136
|
|
|
129
137
|
// if no plugin provides an entry we load it from the app
|
|
@@ -152,7 +160,8 @@ export async function loadFn(
|
|
|
152
160
|
return [entry, template] as [Entry, TemplateModule];
|
|
153
161
|
})();
|
|
154
162
|
|
|
155
|
-
const
|
|
163
|
+
const eventsLoadGlobalData = cr.events.trigger('loadGlobalData', cr);
|
|
164
|
+
const pluginsLoadGlobalData = cr.plugins.z_loadGlobalData(cr);
|
|
156
165
|
|
|
157
166
|
// loading progress is at 20%
|
|
158
167
|
loadOpts?.setProgress(0.2);
|
|
@@ -160,6 +169,7 @@ export async function loadFn(
|
|
|
160
169
|
const loadGlobalDataProm = Promise.all([
|
|
161
170
|
globalProm,
|
|
162
171
|
entryProm,
|
|
172
|
+
...eventsLoadGlobalData,
|
|
163
173
|
...pluginsLoadGlobalData,
|
|
164
174
|
]);
|
|
165
175
|
|
|
@@ -167,7 +177,7 @@ export async function loadFn(
|
|
|
167
177
|
// we force resolve them to prevent deadlocks
|
|
168
178
|
if (
|
|
169
179
|
import.meta.env.DEV &&
|
|
170
|
-
!(await Promise.
|
|
180
|
+
!(await Promise.race([loadGlobalDataProm, timeout(2000)]))
|
|
171
181
|
) {
|
|
172
182
|
console.error(
|
|
173
183
|
'DEV: globals took longer than 2 seconds to load. ' +
|
|
@@ -184,8 +194,6 @@ export async function loadFn(
|
|
|
184
194
|
// loading progress is at 60%
|
|
185
195
|
loadOpts?.setProgress(0.6);
|
|
186
196
|
|
|
187
|
-
const pluginsLoadData = cr.events.trigger('loadData', cr, entry);
|
|
188
|
-
|
|
189
197
|
let loadDataProm = null;
|
|
190
198
|
if (template.loadData) {
|
|
191
199
|
loadDataProm = callLoadData(template.loadData, cr, entry);
|
|
@@ -196,9 +204,13 @@ export async function loadFn(
|
|
|
196
204
|
entryDataProm = callLoadData(app.loadEntryData, cr, entry);
|
|
197
205
|
}
|
|
198
206
|
|
|
207
|
+
const eventsLoadData = cr.events.trigger('loadData', cr, entry);
|
|
208
|
+
const pluginsLoadData = cr.plugins.z_loadData(cr);
|
|
209
|
+
|
|
199
210
|
const [templateData, entryData] = await Promise.all([
|
|
200
211
|
loadDataProm,
|
|
201
212
|
entryDataProm,
|
|
213
|
+
...eventsLoadData,
|
|
202
214
|
...pluginsLoadData,
|
|
203
215
|
]);
|
|
204
216
|
|
package/src/loadData/Globals.ts
CHANGED
|
@@ -131,7 +131,7 @@ export default class Globals {
|
|
|
131
131
|
* @hidden
|
|
132
132
|
* call this before starting the loadGlobalData phase
|
|
133
133
|
*/
|
|
134
|
-
z_toRequest() {
|
|
134
|
+
z_toRequest(): Globals {
|
|
135
135
|
const nGlobals = new Globals(this.stores);
|
|
136
136
|
nGlobals.waiters = new Map();
|
|
137
137
|
nGlobals.newData = new Map();
|
package/src/node/index.ts
CHANGED
|
@@ -166,7 +166,7 @@ export default async function createServer(serverMod: any, buildTime: string) {
|
|
|
166
166
|
} catch (e) {
|
|
167
167
|
basicError(res, e);
|
|
168
168
|
}
|
|
169
|
-
}).listen(8080);
|
|
169
|
+
}).listen(process.env.PORT ?? 8080);
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
function basicError(res: ServerResponse, err: any) {
|
package/src/plugins/Events.ts
CHANGED
|
@@ -32,6 +32,9 @@ export default class Events {
|
|
|
32
32
|
* Will be executed in preload as well.
|
|
33
33
|
*
|
|
34
34
|
* @returns a function to remove the listener
|
|
35
|
+
*
|
|
36
|
+
* #### afterRender
|
|
37
|
+
* Note this will also be executed when disableLoadData is true
|
|
35
38
|
*/
|
|
36
39
|
// override this function to add your own function signatures
|
|
37
40
|
on(
|
|
@@ -40,7 +43,7 @@ export default class Events {
|
|
|
40
43
|
): () => void;
|
|
41
44
|
on(
|
|
42
45
|
ev: 'loadGlobalData',
|
|
43
|
-
fn: (cr: CrelteRequest) => Promise<any
|
|
46
|
+
fn: (cr: CrelteRequest) => Promise<any> | any,
|
|
44
47
|
): () => void;
|
|
45
48
|
on(
|
|
46
49
|
ev: 'loadEntry',
|
|
@@ -52,13 +55,20 @@ export default class Events {
|
|
|
52
55
|
): () => void;
|
|
53
56
|
on(
|
|
54
57
|
ev: 'afterLoadEntry',
|
|
55
|
-
fn: (cr: CrelteRequest) => Promise<any
|
|
58
|
+
fn: (cr: CrelteRequest) => Promise<any> | any,
|
|
56
59
|
): () => void;
|
|
57
60
|
on(
|
|
58
61
|
ev: 'loadData',
|
|
59
|
-
fn: (cr: CrelteRequest, entry: Entry) => Promise<any
|
|
62
|
+
fn: (cr: CrelteRequest, entry: Entry) => Promise<any> | any,
|
|
63
|
+
): () => void;
|
|
64
|
+
on(
|
|
65
|
+
ev: 'beforeRender',
|
|
66
|
+
fn: (cr: CrelteRequest, route: Route) => void,
|
|
67
|
+
): () => void;
|
|
68
|
+
on(
|
|
69
|
+
ev: 'afterRender',
|
|
70
|
+
fn: (cr: CrelteRequest, route: Route) => void,
|
|
60
71
|
): () => void;
|
|
61
|
-
on(ev: 'beforeRender', fn: (cr: CrelteRequest) => void): () => void;
|
|
62
72
|
on(ev: string, fn: (...args: any[]) => any): () => void {
|
|
63
73
|
let set = this.inner.get(ev);
|
|
64
74
|
if (!set) {
|
|
@@ -95,15 +105,20 @@ export default class Events {
|
|
|
95
105
|
* Trigger an event
|
|
96
106
|
*/
|
|
97
107
|
trigger(ev: 'beforeRequest', cr: CrelteRequest): (Promise<void> | void)[];
|
|
98
|
-
trigger(ev: 'loadGlobalData', cr: CrelteRequest): Promise<any>[];
|
|
108
|
+
trigger(ev: 'loadGlobalData', cr: CrelteRequest): (Promise<any> | any)[];
|
|
99
109
|
trigger(
|
|
100
110
|
ev: 'beforeQueryEntry',
|
|
101
111
|
cr: CrelteRequest,
|
|
102
112
|
vars: EntryQueryVars,
|
|
103
113
|
): (Promise<void> | void)[];
|
|
104
|
-
trigger(ev: 'afterLoadEntry', cr: CrelteRequest): Promise<any>[];
|
|
105
|
-
trigger(
|
|
114
|
+
trigger(ev: 'afterLoadEntry', cr: CrelteRequest): (Promise<any> | any)[];
|
|
115
|
+
trigger(
|
|
116
|
+
ev: 'loadData',
|
|
117
|
+
cr: CrelteRequest,
|
|
118
|
+
entry: Entry,
|
|
119
|
+
): (Promise<any> | any)[];
|
|
106
120
|
trigger(ev: 'beforeRender', cr: CrelteRequest, route: Route): void[];
|
|
121
|
+
trigger(ev: 'afterRender', cr: CrelteRequest, route: Route): void[];
|
|
107
122
|
trigger(ev: string, ...args: any[]): any[] {
|
|
108
123
|
const set = this.inner.get(ev);
|
|
109
124
|
if (!set) return [];
|
package/src/plugins/Plugins.ts
CHANGED
|
@@ -1,10 +1,32 @@
|
|
|
1
|
-
import { Crelte } from '../crelte.js';
|
|
1
|
+
import { Crelte, CrelteRequest } from '../crelte.js';
|
|
2
|
+
import { Request, Route } from '../routing/index.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* A plugin
|
|
5
6
|
*/
|
|
6
7
|
export interface Plugin {
|
|
7
8
|
name: string;
|
|
9
|
+
/**
|
|
10
|
+
* The returned value will be used inside of CrelteRequest
|
|
11
|
+
*/
|
|
12
|
+
toRequest?: (req: Request) => Plugin;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* This will be called during the loadGlobalData phase.
|
|
16
|
+
*/
|
|
17
|
+
loadGlobalData?: (cr: CrelteRequest) => Promise<void> | void;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* This will be called during the loadData phase.
|
|
21
|
+
*/
|
|
22
|
+
loadData?: (cr: CrelteRequest) => Promise<void> | void;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* This will be called before the dom gets updated.
|
|
26
|
+
*
|
|
27
|
+
* At this point you can update variables or stores.
|
|
28
|
+
*/
|
|
29
|
+
render?: (cr: CrelteRequest, route: Route) => void;
|
|
8
30
|
}
|
|
9
31
|
|
|
10
32
|
/**
|
|
@@ -46,4 +68,47 @@ export default class Plugins {
|
|
|
46
68
|
get(name: string): Plugin | null {
|
|
47
69
|
return this.plugins.get(name) ?? null;
|
|
48
70
|
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @hidden
|
|
74
|
+
*/
|
|
75
|
+
z_toRequest(req: Request): Plugins {
|
|
76
|
+
const nPlugins = new Plugins();
|
|
77
|
+
|
|
78
|
+
for (let plugin of this.plugins.values()) {
|
|
79
|
+
if (typeof plugin.toRequest === 'function')
|
|
80
|
+
plugin = plugin.toRequest(req);
|
|
81
|
+
|
|
82
|
+
nPlugins.add(plugin);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return nPlugins;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @hidden
|
|
90
|
+
*/
|
|
91
|
+
z_loadGlobalData(cr: CrelteRequest): (Promise<void> | void | undefined)[] {
|
|
92
|
+
return Array.from(this.plugins.values()).map(plugin =>
|
|
93
|
+
plugin.loadGlobalData?.(cr),
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @hidden
|
|
99
|
+
*/
|
|
100
|
+
z_loadData(cr: CrelteRequest): (Promise<void> | void | undefined)[] {
|
|
101
|
+
return Array.from(this.plugins.values()).map(plugin =>
|
|
102
|
+
plugin.loadData?.(cr),
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @hidden
|
|
108
|
+
*/
|
|
109
|
+
z_render(cr: CrelteRequest, route: Route): void {
|
|
110
|
+
for (const plugin of this.plugins.values()) {
|
|
111
|
+
plugin.render?.(cr, route);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
49
114
|
}
|
package/src/queries/Queries.ts
CHANGED
|
@@ -17,17 +17,35 @@ export type QueriesOptions = {
|
|
|
17
17
|
/**
|
|
18
18
|
* A GraphQL query
|
|
19
19
|
*
|
|
20
|
-
* You should almost never
|
|
21
|
-
*
|
|
20
|
+
* **You should almost never**
|
|
21
|
+
*
|
|
22
|
+
* When importing a graphql file you will get a {@link NamedQuery}
|
|
23
|
+
* or use the {@link gql} template function to create
|
|
24
|
+
* an {@link InlineQuery}.
|
|
25
|
+
* Alternatively you can use the {@link namedQuery} function to create
|
|
26
|
+
* a {@link NamedQuery}.
|
|
27
|
+
*/
|
|
28
|
+
export type Query = InlineQuery | NamedQuery;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* You should never create this type directly. It is returned from
|
|
32
|
+
* the {@link gql} template function.
|
|
33
|
+
*/
|
|
34
|
+
export type InlineQuery = { path?: string; query: string };
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Always create this object via the {@link namedQuery} function
|
|
38
|
+
*/
|
|
39
|
+
export type NamedQuery = { queryName: string };
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Create a NamedQuery for the given server query name.
|
|
43
|
+
*
|
|
44
|
+
* Prefer importing a graphql file instead.
|
|
22
45
|
*/
|
|
23
|
-
export
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
query: string;
|
|
27
|
-
}
|
|
28
|
-
| {
|
|
29
|
-
queryName: string;
|
|
30
|
-
};
|
|
46
|
+
export function namedQuery(name: string): NamedQuery {
|
|
47
|
+
return { queryName: name };
|
|
48
|
+
}
|
|
31
49
|
|
|
32
50
|
/** Returns true if the passed object is a GraphQlQuery */
|
|
33
51
|
export function isQuery(obj: any): obj is Query {
|
|
@@ -102,8 +120,8 @@ export default class Queries {
|
|
|
102
120
|
*/
|
|
103
121
|
static new(
|
|
104
122
|
endpoint: string,
|
|
105
|
-
frontend: string,
|
|
106
|
-
ssrCache: SsrCache,
|
|
123
|
+
frontend: string | null = null,
|
|
124
|
+
ssrCache: SsrCache = new SsrCache(),
|
|
107
125
|
opts: QueriesOptions = {},
|
|
108
126
|
): Queries {
|
|
109
127
|
return new Queries(
|
|
@@ -113,6 +131,18 @@ export default class Queries {
|
|
|
113
131
|
);
|
|
114
132
|
}
|
|
115
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Create a new Queries instance that always intented to call an
|
|
136
|
+
* external GraphQl endpoint.
|
|
137
|
+
*/
|
|
138
|
+
static newExternal(endpoint: string, bearerToken?: string): Queries {
|
|
139
|
+
return new Queries(
|
|
140
|
+
new Inner(endpoint, null, new SsrCache(), { bearerToken }),
|
|
141
|
+
null,
|
|
142
|
+
null,
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
116
146
|
/**
|
|
117
147
|
* Run a GraphQl Query
|
|
118
148
|
*
|
|
@@ -170,7 +200,7 @@ type InnerQueryOptions = {
|
|
|
170
200
|
|
|
171
201
|
class Inner {
|
|
172
202
|
endpoint: string;
|
|
173
|
-
frontend: string;
|
|
203
|
+
frontend: string | null;
|
|
174
204
|
ssrCache: SsrCache;
|
|
175
205
|
private listeners: Map<
|
|
176
206
|
string,
|
|
@@ -184,7 +214,7 @@ class Inner {
|
|
|
184
214
|
|
|
185
215
|
constructor(
|
|
186
216
|
endpoint: string,
|
|
187
|
-
frontend: string,
|
|
217
|
+
frontend: string | null,
|
|
188
218
|
ssrCache: SsrCache,
|
|
189
219
|
opts: QueriesOptions = {},
|
|
190
220
|
) {
|
|
@@ -264,6 +294,9 @@ class Inner {
|
|
|
264
294
|
let logName: string, url: URL;
|
|
265
295
|
|
|
266
296
|
if ('queryName' in query) {
|
|
297
|
+
if (!this.frontend)
|
|
298
|
+
throw new Error('only inline queries supported');
|
|
299
|
+
|
|
267
300
|
logName = `query (server: ${query.queryName})`;
|
|
268
301
|
url = new URL(this.frontend);
|
|
269
302
|
url.pathname = '/queries/' + query.queryName;
|
package/src/queries/gql.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { InlineQuery, isQuery } from './Queries.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Create a GraphQL query string with variables.
|
|
@@ -13,7 +13,7 @@ import { isQuery, Query } from './Queries.js';
|
|
|
13
13
|
export function gql(
|
|
14
14
|
strings: TemplateStringsArray | string[] | string,
|
|
15
15
|
...keys: unknown[]
|
|
16
|
-
):
|
|
16
|
+
): InlineQuery {
|
|
17
17
|
if (typeof strings === 'string') strings = [strings];
|
|
18
18
|
|
|
19
19
|
let query = '';
|
package/src/queries/index.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import Queries, {
|
|
2
|
+
InlineQuery,
|
|
2
3
|
isQuery,
|
|
4
|
+
namedQuery,
|
|
5
|
+
NamedQuery,
|
|
3
6
|
QueriesOptions,
|
|
4
7
|
Query,
|
|
5
8
|
QueryOptions,
|
|
6
9
|
} from '../queries/Queries.js';
|
|
10
|
+
import type CrelteServerRequest from '../server/CrelteServer.js';
|
|
7
11
|
import { gql } from './gql.js';
|
|
8
12
|
import QueryError, { QueryErrorResponse } from './QueryError.js';
|
|
9
13
|
import { QueryVar, ValidIf, vars, varsIdsEqual } from './vars.js';
|
|
@@ -13,6 +17,9 @@ export {
|
|
|
13
17
|
type QueriesOptions,
|
|
14
18
|
type QueryOptions,
|
|
15
19
|
type Query,
|
|
20
|
+
type InlineQuery as GqlQuery,
|
|
21
|
+
type NamedQuery,
|
|
22
|
+
namedQuery,
|
|
16
23
|
isQuery,
|
|
17
24
|
QueryError,
|
|
18
25
|
type QueryErrorResponse,
|
|
@@ -32,6 +39,8 @@ export type InferVariableTypes<T> = {
|
|
|
32
39
|
};
|
|
33
40
|
|
|
34
41
|
/**
|
|
42
|
+
* Defines when a query can safely be cached.
|
|
43
|
+
*
|
|
35
44
|
* #### Example
|
|
36
45
|
* ```ts
|
|
37
46
|
* import { vars, Caching } from 'crelte/queries';
|
|
@@ -48,3 +57,65 @@ export type InferVariableTypes<T> = {
|
|
|
48
57
|
export type Caching<
|
|
49
58
|
T extends Record<string, QueryVar<any>> = Record<string, QueryVar<any>>,
|
|
50
59
|
> = boolean | ((response: any, vars: InferVariableTypes<T>) => boolean);
|
|
60
|
+
|
|
61
|
+
/** use {@link Transfrom} */
|
|
62
|
+
export type TransformFn<
|
|
63
|
+
T extends Record<string, QueryVar<any>> = Record<string, QueryVar<any>>,
|
|
64
|
+
> = (
|
|
65
|
+
response: any,
|
|
66
|
+
vars: InferVariableTypes<T>,
|
|
67
|
+
) => void | any | Promise<void | any>;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Transforms the query response before it is returned or cached.
|
|
71
|
+
*
|
|
72
|
+
* #### Example
|
|
73
|
+
* ```ts
|
|
74
|
+
* export const transform: Transform<typeof variables> = (response, vars) => {
|
|
75
|
+
* for (const entry of response.entries) {
|
|
76
|
+
* entry.title = entry.title.toUpperCase();
|
|
77
|
+
* }
|
|
78
|
+
* };
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export type Transform<
|
|
82
|
+
T extends Record<string, QueryVar<any>> = Record<string, QueryVar<any>>,
|
|
83
|
+
F extends TransformFn<T> = TransformFn<T>,
|
|
84
|
+
> = (response: any, vars: InferVariableTypes<T>) => Awaited<ReturnType<F>>;
|
|
85
|
+
|
|
86
|
+
/** use {@link Handle} */
|
|
87
|
+
export type HandleFn<
|
|
88
|
+
T extends Record<string, QueryVar<any>> = Record<string, QueryVar<any>>,
|
|
89
|
+
> = (csr: CrelteServerRequest, vars: InferVariableTypes<T>) => any;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Handles a query request.
|
|
93
|
+
*
|
|
94
|
+
* #### Example
|
|
95
|
+
* ```ts
|
|
96
|
+
* // queries/custom.ts
|
|
97
|
+
* import { vars, type Handle, gql, namedQuery } from 'crelte/queries';
|
|
98
|
+
*
|
|
99
|
+
* // It is good practice to have the query name inside the file
|
|
100
|
+
* export const customQuery = namedQuery('custom');
|
|
101
|
+
*
|
|
102
|
+
* export const variables = {
|
|
103
|
+
* name: vars.string(),
|
|
104
|
+
* };
|
|
105
|
+
*
|
|
106
|
+
* export const handle: Handle<typeof variables> = async (csr, vars) => {
|
|
107
|
+
* if (vars.name === 'demo') {
|
|
108
|
+
* throw new Response('not allowed', { status: 400 });
|
|
109
|
+
* }
|
|
110
|
+
*
|
|
111
|
+
* return { name: vars.name };
|
|
112
|
+
* };
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
export type Handle<
|
|
116
|
+
T extends Record<string, QueryVar<any>> = Record<string, QueryVar<any>>,
|
|
117
|
+
F extends HandleFn<T> = HandleFn<T>,
|
|
118
|
+
> = (
|
|
119
|
+
csr: CrelteServerRequest,
|
|
120
|
+
vars: InferVariableTypes<T>,
|
|
121
|
+
) => Awaited<ReturnType<F>>;
|