crelte 0.1.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.
- package/LICENSE.md +41 -0
- package/dist/Crelte.d.ts +55 -0
- package/dist/Crelte.d.ts.map +1 -0
- package/dist/Crelte.js +106 -0
- package/dist/CrelteBase.d.ts +16 -0
- package/dist/CrelteBase.d.ts.map +1 -0
- package/dist/CrelteBase.js +1 -0
- package/dist/CrelteRouted.d.ts +50 -0
- package/dist/CrelteRouted.d.ts.map +1 -0
- package/dist/CrelteRouted.js +88 -0
- package/dist/blocks/Blocks.d.ts +35 -0
- package/dist/blocks/Blocks.d.ts.map +1 -0
- package/dist/blocks/Blocks.js +100 -0
- package/dist/blocks/Blocks.svelte +21 -0
- package/dist/blocks/Blocks.svelte.d.ts +24 -0
- package/dist/blocks/Blocks.svelte.d.ts.map +1 -0
- package/dist/blocks/index.d.ts +5 -0
- package/dist/blocks/index.d.ts.map +1 -0
- package/dist/blocks/index.js +3 -0
- package/dist/cookies/ClientCookies.d.ts +9 -0
- package/dist/cookies/ClientCookies.d.ts.map +1 -0
- package/dist/cookies/ClientCookies.js +22 -0
- package/dist/cookies/ServerCookies.d.ts +13 -0
- package/dist/cookies/ServerCookies.d.ts.map +1 -0
- package/dist/cookies/ServerCookies.js +31 -0
- package/dist/cookies/index.d.ts +20 -0
- package/dist/cookies/index.d.ts.map +1 -0
- package/dist/cookies/index.js +1 -0
- package/dist/cookies/utils.d.ts +12 -0
- package/dist/cookies/utils.d.ts.map +1 -0
- package/dist/cookies/utils.js +32 -0
- package/dist/graphql/GraphQl.d.ts +60 -0
- package/dist/graphql/GraphQl.d.ts.map +1 -0
- package/dist/graphql/GraphQl.js +197 -0
- package/dist/graphql/gql.test.d.ts +2 -0
- package/dist/graphql/gql.test.d.ts.map +1 -0
- package/dist/graphql/gql.test.js +80 -0
- package/dist/graphql/index.d.ts +3 -0
- package/dist/graphql/index.d.ts.map +1 -0
- package/dist/graphql/index.js +2 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +83 -0
- package/dist/init/client.d.ts +13 -0
- package/dist/init/client.d.ts.map +1 -0
- package/dist/init/client.js +129 -0
- package/dist/init/server.d.ts +38 -0
- package/dist/init/server.d.ts.map +1 -0
- package/dist/init/server.js +95 -0
- package/dist/init/shared.d.ts +29 -0
- package/dist/init/shared.d.ts.map +1 -0
- package/dist/init/shared.js +154 -0
- package/dist/loadData/Globals.d.ts +33 -0
- package/dist/loadData/Globals.d.ts.map +1 -0
- package/dist/loadData/Globals.js +119 -0
- package/dist/loadData/index.d.ts +25 -0
- package/dist/loadData/index.d.ts.map +1 -0
- package/dist/loadData/index.js +39 -0
- package/dist/plugins/Events.d.ts +11 -0
- package/dist/plugins/Events.d.ts.map +1 -0
- package/dist/plugins/Events.js +29 -0
- package/dist/plugins/Plugins.d.ts +12 -0
- package/dist/plugins/Plugins.d.ts.map +1 -0
- package/dist/plugins/Plugins.js +12 -0
- package/dist/plugins/index.d.ts +5 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +2 -0
- package/dist/routing/History.d.ts +22 -0
- package/dist/routing/History.d.ts.map +1 -0
- package/dist/routing/History.js +36 -0
- package/dist/routing/InnerRouter.d.ts +111 -0
- package/dist/routing/InnerRouter.d.ts.map +1 -0
- package/dist/routing/InnerRouter.js +397 -0
- package/dist/routing/PageLoader.d.ts +37 -0
- package/dist/routing/PageLoader.d.ts.map +1 -0
- package/dist/routing/PageLoader.js +72 -0
- package/dist/routing/Route.d.ts +82 -0
- package/dist/routing/Route.d.ts.map +1 -0
- package/dist/routing/Route.js +134 -0
- package/dist/routing/Router.d.ts +162 -0
- package/dist/routing/Router.d.ts.map +1 -0
- package/dist/routing/Router.js +333 -0
- package/dist/routing/Site.d.ts +47 -0
- package/dist/routing/Site.d.ts.map +1 -0
- package/dist/routing/Site.js +48 -0
- package/dist/routing/index.d.ts +5 -0
- package/dist/routing/index.d.ts.map +1 -0
- package/dist/routing/index.js +4 -0
- package/dist/ssr/SsrCache.d.ts +12 -0
- package/dist/ssr/SsrCache.d.ts.map +1 -0
- package/dist/ssr/SsrCache.js +50 -0
- package/dist/ssr/SsrComponents.d.ts +7 -0
- package/dist/ssr/SsrComponents.d.ts.map +1 -0
- package/dist/ssr/SsrComponents.js +30 -0
- package/dist/ssr/index.d.ts +4 -0
- package/dist/ssr/index.d.ts.map +1 -0
- package/dist/ssr/index.js +3 -0
- package/package.json +79 -0
- package/src/Crelte.ts +135 -0
- package/src/CrelteBase.ts +24 -0
- package/src/CrelteRouted.ts +128 -0
- package/src/blocks/Blocks.svelte +68 -0
- package/src/blocks/Blocks.ts +155 -0
- package/src/blocks/index.ts +14 -0
- package/src/cookies/ClientCookies.ts +30 -0
- package/src/cookies/ServerCookies.ts +42 -0
- package/src/cookies/index.ts +24 -0
- package/src/cookies/utils.ts +53 -0
- package/src/graphql/GraphQl.ts +281 -0
- package/src/graphql/gql.test.ts +123 -0
- package/src/graphql/index.ts +8 -0
- package/src/index.ts +109 -0
- package/src/init/client.ts +190 -0
- package/src/init/server.ts +177 -0
- package/src/init/shared.ts +221 -0
- package/src/loadData/Globals.ts +150 -0
- package/src/loadData/index.ts +67 -0
- package/src/plugins/Events.ts +50 -0
- package/src/plugins/Plugins.ts +23 -0
- package/src/plugins/index.ts +5 -0
- package/src/routing/History.ts +52 -0
- package/src/routing/InnerRouter.ts +469 -0
- package/src/routing/PageLoader.ts +112 -0
- package/src/routing/Route.ts +184 -0
- package/src/routing/Router.ts +476 -0
- package/src/routing/Site.ts +65 -0
- package/src/routing/index.ts +5 -0
- package/src/ssr/SsrCache.ts +61 -0
- package/src/ssr/SsrComponents.ts +34 -0
- package/src/ssr/index.ts +4 -0
package/src/Crelte.ts
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import ClientCookies from './cookies/ClientCookies.js';
|
|
2
|
+
import { Cookies } from './cookies/index.js';
|
|
3
|
+
import ServerCookies from './cookies/ServerCookies.js';
|
|
4
|
+
import CrelteBase from './CrelteBase.js';
|
|
5
|
+
import CrelteRouted, { GraphQlQuery } from './CrelteRouted.js';
|
|
6
|
+
import GraphQl, {
|
|
7
|
+
GraphQlOptions,
|
|
8
|
+
GraphQlRequestOptions,
|
|
9
|
+
} from './graphql/GraphQl.js';
|
|
10
|
+
import Globals from './loadData/Globals.js';
|
|
11
|
+
import Events from './plugins/Events.js';
|
|
12
|
+
import Plugins, { Plugin } from './plugins/Plugins.js';
|
|
13
|
+
import Route from './routing/Route.js';
|
|
14
|
+
import Router, { RouterOpts } from './routing/Router.js';
|
|
15
|
+
import Site, { SiteFromGraphQl } from './routing/Site.js';
|
|
16
|
+
import SsrCache from './ssr/SsrCache.js';
|
|
17
|
+
|
|
18
|
+
export class CrelteBuilder {
|
|
19
|
+
ssrCache: SsrCache;
|
|
20
|
+
plugins: Plugins;
|
|
21
|
+
events: Events;
|
|
22
|
+
graphQl?: GraphQl;
|
|
23
|
+
router?: Router;
|
|
24
|
+
globals: Globals;
|
|
25
|
+
cookies: Cookies;
|
|
26
|
+
|
|
27
|
+
constructor() {
|
|
28
|
+
this.ssrCache = new SsrCache();
|
|
29
|
+
this.plugins = new Plugins();
|
|
30
|
+
this.events = new Events();
|
|
31
|
+
this.globals = new Globals();
|
|
32
|
+
// @ts-ignore
|
|
33
|
+
this.cookies = import.meta.env.SSR
|
|
34
|
+
? new ServerCookies()
|
|
35
|
+
: new ClientCookies();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
setupGraphQl(endpoint: string, opts: GraphQlOptions = {}) {
|
|
39
|
+
this.graphQl = new GraphQl(endpoint, this.ssrCache, opts);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
setupRouter(sites: SiteFromGraphQl[], opts: RouterOpts = {}) {
|
|
43
|
+
this.router = new Router(sites, opts);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
setupCookies(cookies: string) {
|
|
47
|
+
this.cookies._init(cookies);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
build(): Crelte {
|
|
51
|
+
return new Crelte(this);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default class Crelte implements CrelteBase {
|
|
56
|
+
ssrCache: SsrCache;
|
|
57
|
+
graphQl: GraphQl;
|
|
58
|
+
router: Router;
|
|
59
|
+
plugins: Plugins;
|
|
60
|
+
events: Events;
|
|
61
|
+
globals: Globals;
|
|
62
|
+
cookies: Cookies;
|
|
63
|
+
|
|
64
|
+
constructor(builder: CrelteBuilder) {
|
|
65
|
+
if (!builder.graphQl || !builder.router)
|
|
66
|
+
throw new Error('builder not ready');
|
|
67
|
+
|
|
68
|
+
this.ssrCache = builder.ssrCache;
|
|
69
|
+
this.graphQl = builder.graphQl;
|
|
70
|
+
this.router = builder.router;
|
|
71
|
+
this.plugins = builder.plugins;
|
|
72
|
+
this.events = builder.events;
|
|
73
|
+
this.globals = builder.globals;
|
|
74
|
+
this.cookies = builder.cookies;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
getPlugin(name: string): Plugin | null {
|
|
78
|
+
return this.plugins.get(name);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* returns an env Variables, always needs to be prefixed VITE_
|
|
83
|
+
* Except ENDPOINT_URL and CRAFT_WEB_URL
|
|
84
|
+
*/
|
|
85
|
+
getEnv(name: string): string | null {
|
|
86
|
+
return this.ssrCache.get(name);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/// calling this from loadGlobalData will always return null
|
|
90
|
+
/// this does return the resolved store
|
|
91
|
+
getGlobal(name: string): any | null {
|
|
92
|
+
return this.globals.get(name) ?? null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/// requires a site if the route does not contain a site
|
|
96
|
+
toRouted(route?: Route, site?: Site): CrelteRouted {
|
|
97
|
+
if (!route) {
|
|
98
|
+
route = this.router.route.get();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!site) {
|
|
102
|
+
if (!route.site) throw new Error('site is required');
|
|
103
|
+
site = route.site;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return new CrelteRouted(this, route, site);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Run a GraphQl Query
|
|
111
|
+
*
|
|
112
|
+
* @param query the default export from a graphql file
|
|
113
|
+
* @param variables variables that should be passed to the
|
|
114
|
+
* graphql query
|
|
115
|
+
* @param options opts `{ caching: true, previewToken: string,
|
|
116
|
+
* siteToken: string, ignoreStatusCode: false, headers: {} }`
|
|
117
|
+
*/
|
|
118
|
+
async query(
|
|
119
|
+
query: GraphQlQuery,
|
|
120
|
+
variables: Record<string, unknown> = {},
|
|
121
|
+
opts: GraphQlRequestOptions = {},
|
|
122
|
+
): Promise<unknown> {
|
|
123
|
+
// this function is added as convenience
|
|
124
|
+
return this.toRouted().query(query, variables, opts);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// don't use
|
|
128
|
+
_getContext(): Map<string, any> {
|
|
129
|
+
const map = new Map();
|
|
130
|
+
|
|
131
|
+
map.set('crelte', this);
|
|
132
|
+
|
|
133
|
+
return map;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { GraphQlQuery } from './CrelteRouted.js';
|
|
2
|
+
import { GraphQlRequestOptions } from './graphql/GraphQl.js';
|
|
3
|
+
|
|
4
|
+
// todo or name it CrelteCommon, CrelteShared?
|
|
5
|
+
export default interface CrelteBase {
|
|
6
|
+
/// calling this from loadGlobalData will always return null
|
|
7
|
+
/// this does return the resolved store
|
|
8
|
+
getGlobal(name: string): any | null;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Run a GraphQl Query
|
|
12
|
+
*
|
|
13
|
+
* @param query the default export from a graphql file
|
|
14
|
+
* @param variables variables that should be passed to the
|
|
15
|
+
* graphql query
|
|
16
|
+
* @param options opts `{ caching: true, previewToken: string,
|
|
17
|
+
* siteToken: string, ignoreStatusCode: false, headers: {} }`
|
|
18
|
+
*/
|
|
19
|
+
query(
|
|
20
|
+
query: GraphQlQuery,
|
|
21
|
+
variables?: Record<string, unknown>,
|
|
22
|
+
opts?: GraphQlRequestOptions,
|
|
23
|
+
): Promise<unknown>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { Cookies } from './cookies/index.js';
|
|
2
|
+
import Crelte from './Crelte.js';
|
|
3
|
+
import CrelteBase from './CrelteBase.js';
|
|
4
|
+
import GraphQl, { GraphQlRequestOptions } from './graphql/GraphQl.js';
|
|
5
|
+
import type Globals from './loadData/Globals.js';
|
|
6
|
+
import type Events from './plugins/Events.js';
|
|
7
|
+
import Plugins, { Plugin } from './plugins/Plugins.js';
|
|
8
|
+
import Route from './routing/Route.js';
|
|
9
|
+
import Router from './routing/Router.js';
|
|
10
|
+
import Site from './routing/Site.js';
|
|
11
|
+
import SsrCache from './ssr/SsrCache.js';
|
|
12
|
+
|
|
13
|
+
export type GraphQlQuery = {
|
|
14
|
+
path?: string;
|
|
15
|
+
query: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default class CrelteRouted implements CrelteBase {
|
|
19
|
+
route: Route;
|
|
20
|
+
site: Site;
|
|
21
|
+
|
|
22
|
+
private inner: Crelte;
|
|
23
|
+
private innerGlobals: Map<string, any>;
|
|
24
|
+
|
|
25
|
+
constructor(inner: Crelte, route: Route, site: Site) {
|
|
26
|
+
this.route = route;
|
|
27
|
+
this.site = site;
|
|
28
|
+
|
|
29
|
+
this.inner = inner;
|
|
30
|
+
this.innerGlobals = new Map();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get crelte(): Crelte {
|
|
34
|
+
return this.inner;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get ssrCache(): SsrCache {
|
|
38
|
+
return this.inner.ssrCache;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get plugins(): Plugins {
|
|
42
|
+
return this.inner.plugins;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get events(): Events {
|
|
46
|
+
return this.inner.events;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get graphQl(): GraphQl {
|
|
50
|
+
return this.inner.graphQl;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get router(): Router {
|
|
54
|
+
return this.inner.router;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get globals(): Globals {
|
|
58
|
+
return this.inner.globals;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get cookies(): Cookies {
|
|
62
|
+
return this.inner.cookies;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// overload this function to add your plugin type
|
|
66
|
+
getPlugin(name: string): Plugin | null {
|
|
67
|
+
return this.inner.plugins.get(name);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* returns an env Variables, always needs to be prefixed VITE_
|
|
72
|
+
* Except ENDPOINT_URL and CRAFT_WEB_URL
|
|
73
|
+
*/
|
|
74
|
+
getEnv(name: string): string | null {
|
|
75
|
+
return this.inner.getEnv(name);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/// calling this from loadGlobalData will always return null
|
|
79
|
+
/// this does return the resolved store
|
|
80
|
+
getGlobal(name: string): any | null {
|
|
81
|
+
return this.innerGlobals.get(name) ?? null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/// get a global and wait for it if it is still loaded
|
|
85
|
+
/// this is useful when you need to load a global in the
|
|
86
|
+
/// loadGlobalData function
|
|
87
|
+
async getGlobalAsync(name: string): Promise<any | null> {
|
|
88
|
+
const global = this.innerGlobals.get(name);
|
|
89
|
+
if (global) return global;
|
|
90
|
+
|
|
91
|
+
const r = await this.inner.globals.getAsync(name);
|
|
92
|
+
if (!r) return null;
|
|
93
|
+
|
|
94
|
+
return r.bySiteId(this.site.id);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Run a GraphQl Query
|
|
99
|
+
*
|
|
100
|
+
* @param query the default export from a graphql file
|
|
101
|
+
* @param variables variables that should be passed to the
|
|
102
|
+
* graphql query
|
|
103
|
+
* @param options opts `{ caching: true, previewToken: string,
|
|
104
|
+
* siteToken: string, ignoreStatusCode: false, headers: {} }`
|
|
105
|
+
*/
|
|
106
|
+
async query(
|
|
107
|
+
query: GraphQlQuery,
|
|
108
|
+
variables: Record<string, unknown> = {},
|
|
109
|
+
opts: GraphQlRequestOptions = {},
|
|
110
|
+
): Promise<unknown> {
|
|
111
|
+
const search = this.route.search;
|
|
112
|
+
|
|
113
|
+
if (search.has('token') && search.get('x-craft-live-preview')) {
|
|
114
|
+
opts.previewToken = search.get('token')!;
|
|
115
|
+
} else if (search.has('siteToken')) {
|
|
116
|
+
opts.siteToken = search.get('siteToken')!;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
opts.path = query.path;
|
|
120
|
+
|
|
121
|
+
return await this.graphQl.request(query.query, variables, opts);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// hidden
|
|
125
|
+
_globalDataLoaded() {
|
|
126
|
+
this.innerGlobals = this.inner.globals._globalsBySite(this.site.id);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<script context="module" lang="ts">
|
|
2
|
+
import { CrelteRouted } from '../index.js';
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
usage:
|
|
6
|
+
|
|
7
|
+
const mods = import.meta.glob('./contentDetail/*.svelte', {
|
|
8
|
+
// can either be eager loaded or not
|
|
9
|
+
eager: true,
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const mods = blockModules(
|
|
13
|
+
import.meta.glob('./contentDetail/*.svelte', { eager: true }),
|
|
14
|
+
{
|
|
15
|
+
alias: {
|
|
16
|
+
'contentDetail': 'contentDetail',
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
export const loadData = {
|
|
22
|
+
blocks: (cr, entry) => loadBlocksData(cr, entry.blocks, mods)
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export let blocks;
|
|
26
|
+
|
|
27
|
+
// provide entry if wanted, all $$restProps will be passed to the children
|
|
28
|
+
<Blocks {blocks} {entry} />
|
|
29
|
+
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import Blocks, {
|
|
33
|
+
type AsyncModule,
|
|
34
|
+
type Module,
|
|
35
|
+
type BlockModulesOptions,
|
|
36
|
+
BlockModules,
|
|
37
|
+
newBlocks,
|
|
38
|
+
} from './Blocks.js';
|
|
39
|
+
|
|
40
|
+
export type { BlockModules, BlockModulesOptions, AsyncModule, Module };
|
|
41
|
+
|
|
42
|
+
export function blockModules(
|
|
43
|
+
modules: Record<string, AsyncModule>,
|
|
44
|
+
opts: BlockModulesOptions = {},
|
|
45
|
+
): BlockModules {
|
|
46
|
+
return new BlockModules(modules, opts);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function loadBlocksData(
|
|
50
|
+
cr: CrelteRouted,
|
|
51
|
+
blocks: any[],
|
|
52
|
+
modules: BlockModules,
|
|
53
|
+
): Promise<Blocks> {
|
|
54
|
+
const nBlocks = await newBlocks(blocks, modules);
|
|
55
|
+
|
|
56
|
+
await nBlocks.loadData(cr);
|
|
57
|
+
|
|
58
|
+
return nBlocks;
|
|
59
|
+
}
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<script lang="ts">
|
|
63
|
+
export let blocks: Blocks;
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
{#each blocks.each() as { mod, props }}
|
|
67
|
+
<svelte:component this={mod} {...props} {...$$restProps} />
|
|
68
|
+
{/each}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { CrelteRouted } from '../index.js';
|
|
2
|
+
import { callLoadData } from '../loadData/index.js';
|
|
3
|
+
|
|
4
|
+
export interface Module {
|
|
5
|
+
// svelte component
|
|
6
|
+
default: any;
|
|
7
|
+
handle?: string | string[];
|
|
8
|
+
keepTypeHandle?: boolean;
|
|
9
|
+
|
|
10
|
+
loadData?: (block: any) => Promise<any>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type AsyncModule = (() => Promise<Module>) | Module;
|
|
14
|
+
|
|
15
|
+
export type BlockModulesOptions = {
|
|
16
|
+
// if a block should handle multiple blocks
|
|
17
|
+
alias?: Record<string, string>;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export class BlockModules {
|
|
21
|
+
modules: Map<string, AsyncModule>;
|
|
22
|
+
alias: Map<string, string>;
|
|
23
|
+
|
|
24
|
+
constructor(
|
|
25
|
+
modules: Record<string, AsyncModule>,
|
|
26
|
+
opts: BlockModulesOptions = {},
|
|
27
|
+
) {
|
|
28
|
+
this.modules = new Map(
|
|
29
|
+
Object.entries(modules)
|
|
30
|
+
.map(([path, mod]) => {
|
|
31
|
+
const [name, ext] = parseFilename(path);
|
|
32
|
+
|
|
33
|
+
return [ext === 'svelte' ? name : '', mod] as [
|
|
34
|
+
string,
|
|
35
|
+
AsyncModule,
|
|
36
|
+
];
|
|
37
|
+
})
|
|
38
|
+
.filter(([name, _mod]) => !!name),
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
this.alias = new Map(Object.entries(opts.alias ?? {}));
|
|
42
|
+
|
|
43
|
+
// backwards compatibility allow to use the export const handle
|
|
44
|
+
this.modules.forEach((mod, name) => {
|
|
45
|
+
if (typeof mod === 'function') return;
|
|
46
|
+
|
|
47
|
+
if (mod.handle) {
|
|
48
|
+
const handles = Array.isArray(mod.handle)
|
|
49
|
+
? mod.handle
|
|
50
|
+
: [mod.handle];
|
|
51
|
+
handles.forEach(handle => {
|
|
52
|
+
this.alias.set(handle, name);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Loads the required modules
|
|
60
|
+
*
|
|
61
|
+
* @throws an error if a module is not found
|
|
62
|
+
*/
|
|
63
|
+
async load(requiredModules: Set<string>): Promise<Map<string, Module>> {
|
|
64
|
+
const loaded = await Promise.all(
|
|
65
|
+
[...requiredModules.keys()].map(mod => {
|
|
66
|
+
let module = this.modules.get(mod);
|
|
67
|
+
if (!module)
|
|
68
|
+
module = this.modules.get(this.alias.get(mod) ?? '');
|
|
69
|
+
|
|
70
|
+
if (!module) throw new Error(`Module ${mod} not found`);
|
|
71
|
+
|
|
72
|
+
return typeof module === 'function' ? module() : module;
|
|
73
|
+
}),
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
// todo once loaded override it in module again
|
|
77
|
+
|
|
78
|
+
return new Map<string, Module>(
|
|
79
|
+
[...requiredModules.keys()].map((mod, i) => [mod, loaded[i]]),
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export async function newBlocks(blocks: any[], modules: BlockModules) {
|
|
85
|
+
// define all required modules
|
|
86
|
+
const requiredModules: Set<string> = new Set();
|
|
87
|
+
|
|
88
|
+
for (const block of blocks) {
|
|
89
|
+
if (!block.typeHandle) throw new Error('Block must have a typeHandle');
|
|
90
|
+
|
|
91
|
+
requiredModules.add(block.typeHandle);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const loadedModules = await modules.load(requiredModules);
|
|
95
|
+
|
|
96
|
+
return new Blocks(blocks, loadedModules);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export default class Blocks {
|
|
100
|
+
blocks: any[];
|
|
101
|
+
data: any[];
|
|
102
|
+
modules: Map<string, Module>;
|
|
103
|
+
|
|
104
|
+
constructor(blocks: any[], modules: Map<string, Module>) {
|
|
105
|
+
this.blocks = blocks;
|
|
106
|
+
this.modules = modules;
|
|
107
|
+
this.data = blocks.map(() => null);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async loadData(cr: CrelteRouted) {
|
|
111
|
+
this.data = await Promise.all(
|
|
112
|
+
this.blocks.map((block, i) => {
|
|
113
|
+
const mod = this.modules.get(block.typeHandle)!;
|
|
114
|
+
|
|
115
|
+
if ('loadData' in mod) {
|
|
116
|
+
return callLoadData(mod.loadData, cr, block, {
|
|
117
|
+
getSibling: (offset: number) => {
|
|
118
|
+
return this.blocks[i + offset] ?? null;
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return {};
|
|
124
|
+
}),
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
each(): { mod: any; props: any }[] {
|
|
129
|
+
return this.blocks.map((block, i) => {
|
|
130
|
+
const mod = this.modules.get(block.typeHandle)!;
|
|
131
|
+
|
|
132
|
+
const props = { ...block };
|
|
133
|
+
if (!mod.keepTypeHandle) delete props.typeHandle;
|
|
134
|
+
Object.assign(props, this.data[i]);
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
mod: mod.default,
|
|
138
|
+
props,
|
|
139
|
+
};
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function parseFilename(path: string): [string, string] {
|
|
145
|
+
// get filename with extension
|
|
146
|
+
const slash = path.lastIndexOf('/');
|
|
147
|
+
const filename = path.substring(slash + 1);
|
|
148
|
+
|
|
149
|
+
const extPos = filename.lastIndexOf('.');
|
|
150
|
+
|
|
151
|
+
const name = filename.substring(0, extPos);
|
|
152
|
+
const ext = filename.substring(extPos + 1);
|
|
153
|
+
|
|
154
|
+
return [name, ext];
|
|
155
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import Blocks, {
|
|
2
|
+
type BlockModules,
|
|
3
|
+
type BlockModulesOptions,
|
|
4
|
+
type AsyncModule,
|
|
5
|
+
type Module,
|
|
6
|
+
blockModules,
|
|
7
|
+
loadBlocksData,
|
|
8
|
+
} from './Blocks.svelte';
|
|
9
|
+
|
|
10
|
+
export type { BlockModules, BlockModulesOptions, AsyncModule, Module };
|
|
11
|
+
|
|
12
|
+
export { Blocks, blockModules, loadBlocksData };
|
|
13
|
+
|
|
14
|
+
export default Blocks;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Cookies, SetOptions } from './index.js';
|
|
2
|
+
import { parseCookies, setCookieToString } from './utils.js';
|
|
3
|
+
|
|
4
|
+
// the philosophy here is that document.cookie is the source of truth
|
|
5
|
+
// so we don't cache cookies here
|
|
6
|
+
// if this changes, modify init/client.ts
|
|
7
|
+
export default class ClientCookies implements Cookies {
|
|
8
|
+
constructor() {}
|
|
9
|
+
|
|
10
|
+
_init(_cookies: string): void {}
|
|
11
|
+
|
|
12
|
+
get(name: string): string | null {
|
|
13
|
+
const cookies = getCookies();
|
|
14
|
+
return cookies.get(name) ?? null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
set(name: string, value: string, opts?: SetOptions): void {
|
|
18
|
+
const setCookie = { name, value, ...opts };
|
|
19
|
+
|
|
20
|
+
document.cookie = setCookieToString(setCookie);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
remove(name: string): void {
|
|
24
|
+
this.set(name, '', { maxAge: 0 });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getCookies(): Map<string, string> {
|
|
29
|
+
return parseCookies(document.cookie);
|
|
30
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Cookies, SetOptions } from './index.js';
|
|
2
|
+
import { parseCookies, SetCookie, setCookieToString } from './utils.js';
|
|
3
|
+
|
|
4
|
+
export default class ServerCookies implements Cookies {
|
|
5
|
+
requestCookies: Map<string, string>;
|
|
6
|
+
setCookies: Map<string, SetCookie>;
|
|
7
|
+
|
|
8
|
+
constructor() {
|
|
9
|
+
this.requestCookies = new Map();
|
|
10
|
+
this.setCookies = new Map();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
_init(cookies: string): void {
|
|
14
|
+
// parse the cookies
|
|
15
|
+
this.requestCookies = parseCookies(cookies);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/// Rethrns the value of the cookie with the given name, or null if it doesn't exist.
|
|
19
|
+
get(name: string): string | null {
|
|
20
|
+
const setCookie = this.setCookies.get(name);
|
|
21
|
+
// js allows undefined > 0
|
|
22
|
+
if (setCookie && setCookie.maxAge! > 0) {
|
|
23
|
+
return setCookie.value;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return this.requestCookies.get(name) ?? null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
set(name: string, value: string, opts?: SetOptions): void {
|
|
30
|
+
this.setCookies.set(name, { name, value, ...opts });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
remove(name: string): void {
|
|
34
|
+
this.set(name, '', { maxAge: 0 });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
_getSetCookiesHeaders(): string[] {
|
|
38
|
+
return Array.from(this.setCookies.values()).map(setCookie =>
|
|
39
|
+
setCookieToString(setCookie),
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type SetOptions = {
|
|
2
|
+
maxAge?: number;
|
|
3
|
+
path?: string;
|
|
4
|
+
domain?: string;
|
|
5
|
+
secure?: boolean;
|
|
6
|
+
httpOnly?: boolean;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export interface Cookies {
|
|
10
|
+
/**
|
|
11
|
+
* returns the value of the cookie
|
|
12
|
+
*/
|
|
13
|
+
get(name: string): string | null;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* sets the value of the cookie
|
|
17
|
+
*/
|
|
18
|
+
set(name: string, value: string, opts?: SetOptions): void;
|
|
19
|
+
|
|
20
|
+
remove(name: string): void;
|
|
21
|
+
|
|
22
|
+
// doc hidden
|
|
23
|
+
_init(cookies: string): void;
|
|
24
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export function parseCookies(cookies: string): Map<string, string> {
|
|
2
|
+
return new Map(
|
|
3
|
+
cookies.split(';').map(cookie => {
|
|
4
|
+
let [name, value] = cookie.split('=');
|
|
5
|
+
/// this is the behaviour of chrome
|
|
6
|
+
if (typeof value === 'undefined') {
|
|
7
|
+
value = name;
|
|
8
|
+
name = '';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
name = name.trim();
|
|
12
|
+
value = decodeURIComponent(value.trim());
|
|
13
|
+
|
|
14
|
+
return [name, value];
|
|
15
|
+
}),
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type SetCookie = {
|
|
20
|
+
name: string;
|
|
21
|
+
value: string;
|
|
22
|
+
maxAge?: number;
|
|
23
|
+
path?: string;
|
|
24
|
+
domain?: string;
|
|
25
|
+
secure?: boolean;
|
|
26
|
+
httpOnly?: boolean;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export function setCookieToString(cookie: SetCookie): string {
|
|
30
|
+
let s = `${cookie.name}=${encodeURIComponent(cookie.value)}`;
|
|
31
|
+
|
|
32
|
+
if (typeof cookie.maxAge === 'number') {
|
|
33
|
+
s += `; Max-Age=${cookie.maxAge}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (cookie.path) {
|
|
37
|
+
s += `; Path=${cookie.path}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (cookie.domain) {
|
|
41
|
+
s += `; Domain=${cookie.domain}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (cookie.secure) {
|
|
45
|
+
s += `; Secure`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (cookie.httpOnly) {
|
|
49
|
+
s += `; HttpOnly`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return s;
|
|
53
|
+
}
|