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.
Files changed (133) hide show
  1. package/dist/bodyClass/BodyClass.d.ts +39 -0
  2. package/dist/bodyClass/BodyClass.d.ts.map +1 -0
  3. package/dist/bodyClass/BodyClass.js +51 -0
  4. package/dist/bodyClass/ClientBodyClass.d.ts +12 -0
  5. package/dist/bodyClass/ClientBodyClass.d.ts.map +1 -0
  6. package/dist/bodyClass/ClientBodyClass.js +57 -0
  7. package/dist/bodyClass/ServerBodyClass.d.ts +12 -0
  8. package/dist/bodyClass/ServerBodyClass.d.ts.map +1 -0
  9. package/dist/bodyClass/ServerBodyClass.js +47 -0
  10. package/dist/bodyClass/index.d.ts +2 -0
  11. package/dist/bodyClass/index.d.ts.map +1 -0
  12. package/dist/bodyClass/index.js +1 -0
  13. package/dist/cookies/ClientCookies.d.ts +8 -3
  14. package/dist/cookies/ClientCookies.d.ts.map +1 -1
  15. package/dist/cookies/ClientCookies.js +31 -7
  16. package/dist/cookies/Cookies.d.ts +42 -0
  17. package/dist/cookies/Cookies.d.ts.map +1 -0
  18. package/dist/cookies/Cookies.js +44 -0
  19. package/dist/cookies/ServerCookies.d.ts +3 -2
  20. package/dist/cookies/ServerCookies.d.ts.map +1 -1
  21. package/dist/cookies/ServerCookies.js +6 -4
  22. package/dist/cookies/index.d.ts +1 -25
  23. package/dist/cookies/index.d.ts.map +1 -1
  24. package/dist/cookies/index.js +1 -1
  25. package/dist/crelte.d.ts +7 -1
  26. package/dist/crelte.d.ts.map +1 -1
  27. package/dist/crelte.js +2 -1
  28. package/dist/index.d.ts +13 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +9 -0
  31. package/dist/init/client.d.ts +1 -8
  32. package/dist/init/client.d.ts.map +1 -1
  33. package/dist/init/client.js +26 -24
  34. package/dist/init/server.d.ts.map +1 -1
  35. package/dist/init/server.js +12 -4
  36. package/dist/init/shared.d.ts +1 -0
  37. package/dist/init/shared.d.ts.map +1 -1
  38. package/dist/init/shared.js +16 -5
  39. package/dist/loadData/Globals.d.ts.map +1 -1
  40. package/dist/node/index.js +1 -1
  41. package/dist/plugins/Events.d.ts +12 -7
  42. package/dist/plugins/Events.d.ts.map +1 -1
  43. package/dist/plugins/Plugins.d.ts +36 -1
  44. package/dist/plugins/Plugins.d.ts.map +1 -1
  45. package/dist/plugins/Plugins.js +32 -0
  46. package/dist/queries/Queries.d.ts +30 -5
  47. package/dist/queries/Queries.d.ts.map +1 -1
  48. package/dist/queries/Queries.js +19 -2
  49. package/dist/queries/gql.d.ts +2 -2
  50. package/dist/queries/gql.d.ts.map +1 -1
  51. package/dist/queries/index.d.ts +47 -2
  52. package/dist/queries/index.d.ts.map +1 -1
  53. package/dist/queries/index.js +2 -2
  54. package/dist/queries/vars.d.ts +2 -0
  55. package/dist/queries/vars.d.ts.map +1 -1
  56. package/dist/queries/vars.js +10 -0
  57. package/dist/routing/route/Request.d.ts +1 -1
  58. package/dist/routing/route/Request.d.ts.map +1 -1
  59. package/dist/routing/route/Request.js +7 -3
  60. package/dist/routing/router/BaseRouter.d.ts +2 -1
  61. package/dist/routing/router/BaseRouter.d.ts.map +1 -1
  62. package/dist/routing/router/BaseRouter.js +4 -2
  63. package/dist/routing/router/ClientRouter.d.ts.map +1 -1
  64. package/dist/routing/router/ClientRouter.js +21 -15
  65. package/dist/routing/router/Router.d.ts +2 -1
  66. package/dist/routing/router/Router.d.ts.map +1 -1
  67. package/dist/routing/router/Router.js +10 -13
  68. package/dist/routing/utils.d.ts +1 -0
  69. package/dist/routing/utils.d.ts.map +1 -1
  70. package/dist/routing/utils.js +1 -1
  71. package/dist/server/CrelteServer.d.ts +1 -0
  72. package/dist/server/CrelteServer.d.ts.map +1 -1
  73. package/dist/server/CrelteServer.js +5 -2
  74. package/dist/server/ServerRouter.d.ts.map +1 -1
  75. package/dist/server/ServerRouter.js +17 -7
  76. package/dist/server/queries/QueryGqlRoute.d.ts +28 -0
  77. package/dist/server/queries/QueryGqlRoute.d.ts.map +1 -0
  78. package/dist/server/queries/QueryGqlRoute.js +194 -0
  79. package/dist/server/queries/QueryHandleRoute.d.ts +12 -0
  80. package/dist/server/queries/QueryHandleRoute.d.ts.map +1 -0
  81. package/dist/server/queries/QueryHandleRoute.js +24 -0
  82. package/dist/server/queries/queries.d.ts.map +1 -1
  83. package/dist/server/queries/queries.js +42 -19
  84. package/dist/server/queries/routes.d.ts +7 -30
  85. package/dist/server/queries/routes.d.ts.map +1 -1
  86. package/dist/server/queries/routes.js +13 -199
  87. package/dist/std/stores/StagedWritable.d.ts +48 -0
  88. package/dist/std/stores/StagedWritable.d.ts.map +1 -0
  89. package/dist/std/stores/StagedWritable.js +84 -0
  90. package/dist/std/stores/index.d.ts +2 -1
  91. package/dist/std/stores/index.d.ts.map +1 -1
  92. package/dist/std/stores/index.js +2 -1
  93. package/dist/std/sync/Barrier.js +1 -1
  94. package/dist/utils.d.ts +9 -0
  95. package/dist/utils.d.ts.map +1 -1
  96. package/dist/utils.js +11 -0
  97. package/package.json +5 -1
  98. package/src/bodyClass/BodyClass.ts +72 -0
  99. package/src/bodyClass/ClientBodyClass.ts +62 -0
  100. package/src/bodyClass/ServerBodyClass.ts +65 -0
  101. package/src/bodyClass/index.ts +1 -0
  102. package/src/cookies/ClientCookies.ts +41 -10
  103. package/src/cookies/Cookies.ts +70 -0
  104. package/src/cookies/ServerCookies.ts +9 -6
  105. package/src/cookies/index.ts +5 -29
  106. package/src/crelte.ts +9 -0
  107. package/src/index.ts +15 -1
  108. package/src/init/client.ts +29 -24
  109. package/src/init/server.ts +12 -4
  110. package/src/init/shared.ts +18 -6
  111. package/src/loadData/Globals.ts +1 -1
  112. package/src/node/index.ts +1 -1
  113. package/src/plugins/Events.ts +22 -7
  114. package/src/plugins/Plugins.ts +66 -1
  115. package/src/queries/Queries.ts +47 -14
  116. package/src/queries/gql.ts +2 -2
  117. package/src/queries/index.ts +71 -0
  118. package/src/queries/vars.ts +13 -0
  119. package/src/routing/route/Request.ts +11 -4
  120. package/src/routing/router/BaseRouter.ts +4 -2
  121. package/src/routing/router/ClientRouter.ts +26 -18
  122. package/src/routing/router/Router.ts +10 -11
  123. package/src/routing/utils.ts +1 -1
  124. package/src/server/CrelteServer.ts +4 -2
  125. package/src/server/ServerRouter.ts +18 -7
  126. package/src/server/queries/QueryGqlRoute.ts +224 -0
  127. package/src/server/queries/QueryHandleRoute.ts +37 -0
  128. package/src/server/queries/queries.ts +57 -21
  129. package/src/server/queries/routes.ts +25 -229
  130. package/src/std/stores/StagedWritable.ts +96 -0
  131. package/src/std/stores/index.ts +2 -1
  132. package/src/std/sync/Barrier.ts +1 -1
  133. package/src/utils.ts +15 -0
@@ -0,0 +1,194 @@
1
+ import { vars } from '../../queries/vars.js';
2
+ import { extractEntry } from '../../loadData/index.js';
3
+ import { calcKey } from '../../ssr/index.js';
4
+ import { newError, validateVars } from './routes.js';
5
+ // only internal
6
+ export default class QueryGqlRoute {
7
+ name;
8
+ query;
9
+ vars;
10
+ cacheIfFn;
11
+ transformFn;
12
+ constructor(name, query, args) {
13
+ if (args.cacheIfFn && !vars)
14
+ throw new Error('queryRoute: ' +
15
+ name +
16
+ ' cannot have caching function if there are no ' +
17
+ 'variables defined');
18
+ this.name = name;
19
+ this.query = query;
20
+ this.vars = args.vars;
21
+ this.cacheIfFn = args.cacheIfFn;
22
+ this.transformFn = args.transformFn;
23
+ if (args.preventCaching) {
24
+ if (this.cacheIfFn)
25
+ throw new Error('unreachable');
26
+ // prevent filling defaults
27
+ return;
28
+ }
29
+ // add default vars and cacheIfFn if we know the route
30
+ if (this.name === 'entry')
31
+ this.fillEntryDefaults();
32
+ else if (this.name === 'global')
33
+ this.fillGlobalDefaults();
34
+ else
35
+ this.fillBasicDefaults();
36
+ }
37
+ fillEntryDefaults() {
38
+ if (this.vars)
39
+ return;
40
+ // the _setName step happens in parseVars which happens before setting
41
+ // the defaults, so since we're adding vars here we need to set the name
42
+ // manually
43
+ this.vars = {
44
+ siteId: vars.siteId().z_setName('siteId'),
45
+ uri: vars.string().z_setName('uri'),
46
+ };
47
+ this.cacheIfFn = res => !!extractEntry(res);
48
+ }
49
+ fillGlobalDefaults() {
50
+ if (this.vars)
51
+ return;
52
+ this.vars = { siteId: vars.siteId().z_setName('siteId') };
53
+ this.cacheIfFn = () => true;
54
+ }
55
+ /**
56
+ * This adds caching to queries containing `query {` or
57
+ * `query ($siteId: [QueryArgument) {` without any additional vars
58
+ */
59
+ fillBasicDefaults() {
60
+ if (this.vars)
61
+ return;
62
+ const NO_VAR_TEST = /(^|\s)query\s*{/;
63
+ const SITE_ID_VAR_TEST = /(^|\s)query\s*\(\s*\$siteId\s*:\s*\[\s*QueryArgument\s*\]\s*\)\s*{/;
64
+ if (NO_VAR_TEST.test(this.query)) {
65
+ this.vars = {};
66
+ this.cacheIfFn = () => true;
67
+ }
68
+ else if (SITE_ID_VAR_TEST.test(this.query)) {
69
+ this.vars = { siteId: vars.siteId().z_setName('siteId') };
70
+ this.cacheIfFn = () => true;
71
+ }
72
+ else if (!this.query.includes('query')) {
73
+ // this warning might be shown to mutation queries or subscriptions
74
+ // in that case, the user should explicitly set caching to false
75
+ console.warn(`cannot determine if query (${this.name}) is cacheable, see` +
76
+ ' https://github.com/crelte/crelte/issues/114 for infos');
77
+ }
78
+ }
79
+ async transform(jsonResp, vars) {
80
+ if (!this.transformFn || !jsonResp.data)
81
+ return;
82
+ const transformed = await this.transformFn(jsonResp.data, vars);
83
+ if (typeof transformed !== 'undefined')
84
+ jsonResp.data = transformed;
85
+ }
86
+ async handle(caching, csr) {
87
+ let vars;
88
+ try {
89
+ const reqVars = await csr.req.json();
90
+ vars = validateVars(this.vars, reqVars, caching.router);
91
+ if ('qName' in vars || 'xCraftSite' in vars)
92
+ throw new Error('qName and xCraftSite are reserved variable names');
93
+ }
94
+ catch (e) {
95
+ return newError(e, 400);
96
+ }
97
+ let logInfo = null;
98
+ if (caching.debug) {
99
+ logInfo = `[queries: ${this.name}] vars: ${JSON.stringify(vars)}`;
100
+ }
101
+ let previewToken = null;
102
+ let siteToken = null;
103
+ const reqSearch = new URL(csr.req.url).searchParams;
104
+ if (reqSearch.has('token')) {
105
+ previewToken = reqSearch.get('token');
106
+ }
107
+ else if (reqSearch.has('siteToken')) {
108
+ siteToken = reqSearch.get('siteToken');
109
+ }
110
+ // check for x-craft-site header and pass it on
111
+ const xCraftSite = csr.req.headers.get('X-Craft-Site');
112
+ let cacheKey = null;
113
+ const useCache = !previewToken && caching.isEnabled();
114
+ if (useCache) {
115
+ cacheKey = await calcKey({ ...vars, qName: this.name, xCraftSite });
116
+ const cached = await caching.getCache(cacheKey);
117
+ if (logInfo)
118
+ console.log(`${logInfo} ${cached ? 'hit' : 'miss'}`);
119
+ // we found something in the cache
120
+ if (cached)
121
+ return Response.json(cached);
122
+ }
123
+ const headers = {
124
+ 'Content-Type': 'application/json',
125
+ };
126
+ const auth = csr.getEnv('ENDPOINT_TOKEN');
127
+ if (auth)
128
+ headers['Authorization'] = 'Bearer ' + auth;
129
+ const url = new URL(csr.getEnv('ENDPOINT_URL'));
130
+ if (previewToken)
131
+ url.searchParams.set('token', previewToken);
132
+ if (siteToken)
133
+ url.searchParams.set('siteToken', siteToken);
134
+ const xDebug = csr.req.headers.get('X-Debug');
135
+ if (xDebug)
136
+ headers['X-Debug'] = xDebug;
137
+ if (xCraftSite)
138
+ headers['X-Craft-Site'] = xCraftSite;
139
+ // now execute the gql request
140
+ let resp;
141
+ try {
142
+ resp = await fetch(url, {
143
+ method: 'POST',
144
+ headers,
145
+ body: JSON.stringify({
146
+ query: this.query,
147
+ variables: vars,
148
+ }),
149
+ });
150
+ // if the response is not ok we don't cache anything
151
+ // and just return the response
152
+ if (!resp.ok)
153
+ return resp;
154
+ }
155
+ catch (e) {
156
+ return newError(e, 500);
157
+ }
158
+ const respHeaders = {};
159
+ const xDebugLink = resp.headers.get('X-Debug-Link');
160
+ if (xDebugLink)
161
+ respHeaders['X-Debug'] = xDebugLink;
162
+ let jsonResp;
163
+ try {
164
+ jsonResp = await resp.json();
165
+ if (!jsonResp || typeof jsonResp !== 'object')
166
+ throw new Error('invalid json response');
167
+ await this.transform(jsonResp, vars);
168
+ }
169
+ catch (e) {
170
+ return newError(e, 500);
171
+ }
172
+ // also no caching for errors
173
+ if (jsonResp.errors) {
174
+ return Response.json(jsonResp, { headers: respHeaders });
175
+ }
176
+ // now we have a valid json resp.
177
+ // should we cache it?
178
+ if (cacheKey && this.cacheIfFn?.(jsonResp.data, vars)) {
179
+ try {
180
+ await caching.setCache(cacheKey, jsonResp);
181
+ if (logInfo)
182
+ console.log(logInfo + ' set cache');
183
+ }
184
+ catch (e) {
185
+ console.error('could not cache gql response', e);
186
+ }
187
+ // if caching is enabled but not used we warn
188
+ }
189
+ else if (cacheKey && logInfo) {
190
+ console.warn('!! ' + logInfo + ' caching not allowed');
191
+ }
192
+ return Response.json(jsonResp, { headers: respHeaders });
193
+ }
194
+ }
@@ -0,0 +1,12 @@
1
+ import { QueryVar } from '../../queries/vars.js';
2
+ import CrelteServerRequest from '../CrelteServer.js';
3
+ import ServerRouter from '../ServerRouter.js';
4
+ import { HandleFn } from './routes.js';
5
+ export default class QueryHandleRoute {
6
+ name: string;
7
+ handleFn: HandleFn;
8
+ vars: Record<string, QueryVar> | null;
9
+ constructor(name: string, handleFn: HandleFn, vars: Record<string, QueryVar> | null);
10
+ handle(cs: ServerRouter, csr: CrelteServerRequest): Promise<Response>;
11
+ }
12
+ //# sourceMappingURL=QueryHandleRoute.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryHandleRoute.d.ts","sourceRoot":"","sources":["../../../src/server/queries/QueryHandleRoute.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,mBAAmB,MAAM,oBAAoB,CAAC;AACrD,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAA0B,MAAM,aAAa,CAAC;AAG/D,MAAM,CAAC,OAAO,OAAO,gBAAgB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC;gBAGrC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,IAAI;IAOhC,MAAM,CACX,EAAE,EAAE,YAAY,EAChB,GAAG,EAAE,mBAAmB,GACtB,OAAO,CAAC,QAAQ,CAAC;CAYpB"}
@@ -0,0 +1,24 @@
1
+ import { newError, validateVars } from './routes.js';
2
+ // only internal
3
+ export default class QueryHandleRoute {
4
+ name;
5
+ handleFn;
6
+ vars;
7
+ constructor(name, handleFn, vars) {
8
+ this.name = name;
9
+ this.handleFn = handleFn;
10
+ this.vars = vars;
11
+ }
12
+ async handle(cs, csr) {
13
+ let vars;
14
+ try {
15
+ const reqVars = await csr.req.json();
16
+ vars = validateVars(this.vars, reqVars, cs);
17
+ }
18
+ catch (e) {
19
+ return newError(e, 400);
20
+ }
21
+ const res = await this.handleFn(csr, vars);
22
+ return Response.json({ data: res });
23
+ }
24
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../../src/server/queries/queries.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAI9C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAwB1C,wBAAsB,eAAe,CACpC,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,YAAY,GAClB,OAAO,CAAC,IAAI,CAAC,CAwEf"}
1
+ {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../../src/server/queries/queries.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAI9C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AA6B1C,wBAAsB,eAAe,CACpC,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,YAAY,GAClB,OAAO,CAAC,IAAI,CAAC,CAgGf"}
@@ -1,60 +1,78 @@
1
1
  import QueriesCaching from './QueriesCaching.js';
2
- import { QueryRoute } from './routes.js';
3
2
  import { isQueryVar } from '../../queries/vars.js';
3
+ import QueryHandleRoute from './QueryHandleRoute.js';
4
+ import QueryGqlRoute from './QueryGqlRoute.js';
4
5
  export async function initQueryRoutes(platform, mod, router) {
5
6
  if (typeof mod.queries !== 'object') {
6
- throw new Error("expected `export const queries = import.meta.glob('@/queries/*', { eager: true });` in server.js");
7
+ throw new Error('expected `export const queries = import.meta.glob(' +
8
+ "'@/queries/*', { eager: true });` in server.js");
7
9
  }
8
10
  const debugCaching = !!mod?.debugCaching;
9
11
  const modQueries = mod.queries;
10
- const preRoutes = new Map();
12
+ const routeBuilders = new Map();
11
13
  for (const [file, mq] of Object.entries(modQueries)) {
12
14
  const filename = file.split('/').pop();
13
15
  const dotPos = filename.lastIndexOf('.');
14
16
  const name = filename.substring(0, dotPos);
15
- let preRoute = preRoutes.get(name);
16
- if (!preRoute) {
17
- preRoute = {
17
+ let routeBuilder = routeBuilders.get(name);
18
+ if (!routeBuilder) {
19
+ routeBuilder = {
18
20
  query: null,
19
21
  jsFile: null,
20
22
  vars: null,
21
23
  cacheIfFn: null,
22
24
  preventCaching: false,
23
25
  transformFn: null,
26
+ handleFn: null,
24
27
  };
25
- preRoutes.set(name, preRoute);
28
+ routeBuilders.set(name, routeBuilder);
26
29
  }
27
30
  // set the gql query (this can only happen once)
28
31
  if (filename.endsWith('.graphql')) {
29
- preRoute.query = mq.query.query;
32
+ routeBuilder.query = mq.query.query;
30
33
  continue;
31
34
  }
32
35
  // now check that only one file matches
33
- if (preRoute.jsFile) {
34
- throw new Error(`cannot have two files for the same query ${preRoute.jsFile} and ${filename}`);
36
+ if (routeBuilder.jsFile) {
37
+ throw new Error(`cannot have two files for the same query ${routeBuilder.jsFile} and ${filename}`);
35
38
  }
36
39
  const mts = mq;
37
40
  if (mts.variables) {
38
- preRoute.vars = parseVars(mts.variables);
41
+ routeBuilder.vars = parseVars(mts.variables);
39
42
  }
40
43
  if (mts.caching) {
41
- preRoute.cacheIfFn = parseCaching(mts.caching);
44
+ routeBuilder.cacheIfFn = parseCaching(mts.caching);
42
45
  }
43
46
  else if (typeof mts.caching === 'boolean') {
44
- preRoute.preventCaching = true;
47
+ routeBuilder.preventCaching = true;
45
48
  }
46
49
  if (mts.transform) {
47
- preRoute.transformFn = parseTransform(mts.transform);
50
+ routeBuilder.transformFn = parseTransform(mts.transform);
51
+ }
52
+ if (mts.handle) {
53
+ routeBuilder.handleFn = parseHandle(mts.handle);
48
54
  }
49
55
  }
50
56
  const caching = new QueriesCaching(platform, router, {
51
57
  debug: debugCaching,
52
58
  });
53
- for (const [name, pr] of preRoutes.entries()) {
54
- if (!pr.query)
55
- throw new Error(`no .graphql file for query ${name}`);
56
- const route = new QueryRoute(name, pr.query, pr);
57
- router.post('/queries/' + route.name, async (csr) => route.handle(caching, csr));
59
+ for (const [name, rb] of routeBuilders.entries()) {
60
+ if (rb.query) {
61
+ if (rb.handleFn)
62
+ throw new Error('handle function not supported');
63
+ const route = new QueryGqlRoute(name, rb.query, rb);
64
+ router.post('/queries/' + route.name, csr => route.handle(caching, csr));
65
+ }
66
+ else if (rb.handleFn) {
67
+ if (rb.cacheIfFn || rb.transformFn || rb.preventCaching)
68
+ throw new Error('caching or transform not supported');
69
+ const route = new QueryHandleRoute(name, rb.handleFn, rb.vars);
70
+ router.post('/queries/' + route.name, csr => route.handle(caching.router, csr));
71
+ }
72
+ else {
73
+ throw new Error(`query js/ts ${name} file needs to either have ` +
74
+ 'a .graphql file or a handle function');
75
+ }
58
76
  }
59
77
  }
60
78
  function parseVars(vars) {
@@ -81,3 +99,8 @@ function parseTransform(transform) {
81
99
  throw new Error('transform should be a function');
82
100
  return transform;
83
101
  }
102
+ function parseHandle(handle) {
103
+ if (typeof handle !== 'function')
104
+ throw new Error('handle should be a function');
105
+ return handle;
106
+ }
@@ -1,36 +1,13 @@
1
- import CrelteServerRequest from '../CrelteServer.js';
2
- import QueriesCaching from './QueriesCaching.js';
3
1
  import { QueryVar } from '../../queries/vars.js';
2
+ import CrelteServerRequest from '../CrelteServer.js';
4
3
  import ServerRouter from '../ServerRouter.js';
5
4
  export type CacheIfFn = (response: any, vars: Record<string, any>) => boolean;
6
5
  export type TransformFn = (response: any, vars: Record<string, any>) => void | any | Promise<void | any>;
7
- export type QueryRouteArgs = {
8
- vars: Record<string, QueryVar> | null;
9
- cacheIfFn: CacheIfFn | null;
10
- preventCaching: boolean;
11
- transformFn: TransformFn | null;
12
- };
13
- export declare class QueryRoute {
14
- name: string;
15
- query: string;
16
- vars: Record<string, QueryVar> | null;
17
- cacheIfFn: CacheIfFn | null;
18
- transformFn: TransformFn | null;
19
- constructor(name: string, query: string, args: QueryRouteArgs);
20
- private fillEntryDefaults;
21
- private fillGlobalDefaults;
22
- /**
23
- * This adds caching to queries containing `query {` or
24
- * `query ($siteId: [QueryArgument) {` without any additional vars
25
- */
26
- private fillBasicDefaults;
27
- /**
28
- * Returns the validated variables if some vars where defined
29
- * else just returns all vars
30
- */
31
- validateVars(vars: any, cs: ServerRouter): Record<string, any>;
32
- private transform;
33
- handle(caching: QueriesCaching, csr: CrelteServerRequest): Promise<Response>;
34
- }
6
+ export type HandleFn = (csr: CrelteServerRequest, vars: Record<string, any>) => Promise<any> | any;
7
+ /**
8
+ * Returns the validated variables if some vars where defined
9
+ * else just returns all vars
10
+ */
11
+ export declare function validateVars(qvars: Record<string, QueryVar> | null, vars: any, cs: ServerRouter): Record<string, any>;
35
12
  export declare function newError(e: any, status: number): Response;
36
13
  //# sourceMappingURL=routes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/server/queries/routes.ts"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,MAAM,oBAAoB,CAAC;AACrD,OAAO,cAAc,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAQ,MAAM,uBAAuB,CAAC;AAEvD,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAG9C,MAAM,MAAM,SAAS,GAAG,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC;AAM9E,MAAM,MAAM,WAAW,GAAG,CACzB,QAAQ,EAAE,GAAG,EACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KACrB,IAAI,GAAG,GAAG,GAAG,OAAO,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC;AAEtC,MAAM,MAAM,cAAc,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC;IACtC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;CAChC,CAAC;AAGF,qBAAa,UAAU;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC;IACtC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;gBAEpB,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc;IA2B7D,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,kBAAkB;IAO1B;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAgBzB;;;OAGG;IACH,YAAY,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;YAehD,SAAS;IAUjB,MAAM,CACX,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE,mBAAmB,GACtB,OAAO,CAAC,QAAQ,CAAC;CAkHpB;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,CAEzD"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/server/queries/routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,mBAAmB,MAAM,oBAAoB,CAAC;AACrD,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAE9C,MAAM,MAAM,SAAS,GAAG,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC;AAM9E,MAAM,MAAM,WAAW,GAAG,CACzB,QAAQ,EAAE,GAAG,EACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KACrB,IAAI,GAAG,GAAG,GAAG,OAAO,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC;AAEtC,MAAM,MAAM,QAAQ,GAAG,CACtB,GAAG,EAAE,mBAAmB,EACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KACrB,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;AAExB;;;GAGG;AACH,wBAAgB,YAAY,CAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,IAAI,EACtC,IAAI,EAAE,GAAG,EACT,EAAE,EAAE,YAAY,GACd,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAarB;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,CAEzD"}
@@ -1,203 +1,17 @@
1
- import { vars } from '../../queries/vars.js';
2
- import { extractEntry } from '../../loadData/index.js';
3
- import { calcKey } from '../../ssr/index.js';
4
- // only internal
5
- export class QueryRoute {
6
- name;
7
- query;
8
- vars;
9
- cacheIfFn;
10
- transformFn;
11
- constructor(name, query, args) {
12
- if (args.cacheIfFn && !vars)
13
- throw new Error('queryRoute: ' +
14
- name +
15
- ' cannot have caching function if there are no ' +
16
- 'variables defined');
17
- this.name = name;
18
- this.query = query;
19
- this.vars = args.vars;
20
- this.cacheIfFn = args.cacheIfFn;
21
- this.transformFn = args.transformFn;
22
- if (args.preventCaching) {
23
- if (this.cacheIfFn)
24
- throw new Error('unreachable');
25
- // prevent filling defaults
26
- return;
27
- }
28
- // add default vars and cacheIfFn if we know the route
29
- if (this.name === 'entry')
30
- this.fillEntryDefaults();
31
- else if (this.name === 'global')
32
- this.fillGlobalDefaults();
33
- else
34
- this.fillBasicDefaults();
35
- }
36
- fillEntryDefaults() {
37
- if (this.vars)
38
- return;
39
- // the _setName step happens in parseVars which happens before setting
40
- // the defaults
41
- this.vars = {
42
- siteId: vars.siteId().z_setName('siteId'),
43
- uri: vars.string().z_setName('uri'),
44
- };
45
- this.cacheIfFn = res => !!extractEntry(res);
46
- }
47
- fillGlobalDefaults() {
48
- if (this.vars)
49
- return;
50
- this.vars = { siteId: vars.siteId().z_setName('siteId') };
51
- this.cacheIfFn = () => true;
52
- }
53
- /**
54
- * This adds caching to queries containing `query {` or
55
- * `query ($siteId: [QueryArgument) {` without any additional vars
56
- */
57
- fillBasicDefaults() {
58
- if (this.vars)
59
- return;
60
- const NO_VAR_TEST = /(^|\s)query\s*{/;
61
- const SITE_ID_VAR_TEST = /(^|\s)query\s*\(\s*\$siteId\s*:\s*\[\s*QueryArgument\s*\]\s*\)\s*{/;
62
- if (NO_VAR_TEST.test(this.query)) {
63
- this.vars = {};
64
- this.cacheIfFn = () => true;
65
- }
66
- else if (SITE_ID_VAR_TEST.test(this.query)) {
67
- this.vars = { siteId: vars.siteId().z_setName('siteId') };
68
- this.cacheIfFn = () => true;
69
- }
70
- }
71
- /**
72
- * Returns the validated variables if some vars where defined
73
- * else just returns all vars
74
- */
75
- validateVars(vars, cs) {
76
- if (!vars || typeof vars !== 'object')
77
- throw new Error('expected an object as vars');
78
- if (!this.vars)
79
- return vars;
80
- const nVars = {};
81
- for (const [k, v] of Object.entries(this.vars)) {
82
- nVars[k] = v.validValue(vars[k], cs);
83
- }
84
- return nVars;
85
- }
86
- async transform(jsonResp, vars) {
87
- if (!this.transformFn || !jsonResp.data)
88
- return;
89
- const transformed = await this.transformFn(jsonResp.data, vars);
90
- if (typeof transformed !== 'undefined')
91
- jsonResp.data = transformed;
92
- }
93
- async handle(caching, csr) {
94
- let vars;
95
- try {
96
- const reqVars = await csr.req.json();
97
- vars = this.validateVars(reqVars, caching.router);
98
- if ('qName' in vars || 'xCraftSite' in vars)
99
- throw new Error('qName and xCraftSite are reserved variable names');
100
- }
101
- catch (e) {
102
- return newError(e, 400);
103
- }
104
- let logInfo = null;
105
- if (caching.debug) {
106
- logInfo = `[queries: ${this.name}] vars: ${JSON.stringify(vars)}`;
107
- }
108
- let previewToken = null;
109
- let siteToken = null;
110
- const reqSearch = new URL(csr.req.url).searchParams;
111
- if (reqSearch.has('token')) {
112
- previewToken = reqSearch.get('token');
113
- }
114
- else if (reqSearch.has('siteToken')) {
115
- siteToken = reqSearch.get('siteToken');
116
- }
117
- // check for x-craft-site header and pass it on
118
- const xCraftSite = csr.req.headers.get('X-Craft-Site');
119
- let cacheKey = null;
120
- const useCache = !previewToken && caching.isEnabled();
121
- if (useCache) {
122
- cacheKey = await calcKey({ ...vars, qName: this.name, xCraftSite });
123
- const cached = await caching.getCache(cacheKey);
124
- if (logInfo)
125
- console.log(`${logInfo} ${cached ? 'hit' : 'miss'}`);
126
- // we found something in the cache
127
- if (cached)
128
- return Response.json(cached);
129
- }
130
- const headers = {
131
- 'Content-Type': 'application/json',
132
- };
133
- const auth = csr.getEnv('ENDPOINT_TOKEN');
134
- if (auth)
135
- headers['Authorization'] = 'Bearer ' + auth;
136
- const url = new URL(csr.getEnv('ENDPOINT_URL'));
137
- if (previewToken)
138
- url.searchParams.set('token', previewToken);
139
- if (siteToken)
140
- url.searchParams.set('siteToken', siteToken);
141
- const xDebug = csr.req.headers.get('X-Debug');
142
- if (xDebug)
143
- headers['X-Debug'] = xDebug;
144
- if (xCraftSite)
145
- headers['X-Craft-Site'] = xCraftSite;
146
- // now execute the gql request
147
- let resp;
148
- try {
149
- resp = await fetch(url, {
150
- method: 'POST',
151
- headers,
152
- body: JSON.stringify({
153
- query: this.query,
154
- variables: vars,
155
- }),
156
- });
157
- // if the response is not ok we don't cache anything
158
- // and just return the response
159
- if (!resp.ok)
160
- return resp;
161
- }
162
- catch (e) {
163
- return newError(e, 500);
164
- }
165
- const respHeaders = {};
166
- const xDebugLink = resp.headers.get('X-Debug-Link');
167
- if (xDebugLink)
168
- respHeaders['X-Debug'] = xDebugLink;
169
- let jsonResp;
170
- try {
171
- jsonResp = await resp.json();
172
- if (!jsonResp || typeof jsonResp !== 'object')
173
- throw new Error('invalid json response');
174
- await this.transform(jsonResp, vars);
175
- }
176
- catch (e) {
177
- return newError(e, 500);
178
- }
179
- // also no caching for errors
180
- if (jsonResp.errors) {
181
- return Response.json(jsonResp, { headers: respHeaders });
182
- }
183
- // now we have a valid json resp.
184
- // should we cache it?
185
- if (cacheKey && this.cacheIfFn?.(jsonResp.data, vars)) {
186
- try {
187
- await caching.setCache(cacheKey, jsonResp);
188
- if (logInfo)
189
- console.log(logInfo + ' set cache');
190
- }
191
- catch (e) {
192
- console.error('could not cache gql response', e);
193
- }
194
- // if caching is generally disabled we don't warn
195
- }
196
- else if (cacheKey && logInfo) {
197
- console.warn('!! ' + logInfo + ' caching not allowed');
198
- }
199
- return Response.json(jsonResp, { headers: respHeaders });
1
+ /**
2
+ * Returns the validated variables if some vars where defined
3
+ * else just returns all vars
4
+ */
5
+ export function validateVars(qvars, vars, cs) {
6
+ if (!vars || typeof vars !== 'object')
7
+ throw new Error('expected an object as vars');
8
+ if (!qvars)
9
+ return vars;
10
+ const nVars = {};
11
+ for (const [k, v] of Object.entries(qvars)) {
12
+ nVars[k] = v.validValue(vars[k], cs);
200
13
  }
14
+ return nVars;
201
15
  }
202
16
  export function newError(e, status) {
203
17
  return new Response(e.message, { status });
@@ -0,0 +1,48 @@
1
+ import { CloneableOrPrimitive } from '../index.js';
2
+ import { Readable } from './index.js';
3
+ export default class StagedWritable<T> {
4
+ private inner;
5
+ private mode;
6
+ private staged;
7
+ /**
8
+ * Creates a new StagedWritable
9
+ *
10
+ * @param def A default value
11
+ */
12
+ constructor(def: T);
13
+ /**
14
+ * Returns true if the store is currently staged
15
+ */
16
+ isStaged(): boolean;
17
+ /**
18
+ * Returns a new StagedWritable which is staged and has the same value as the current one
19
+ * To commit the staged value, call `commit` on the returned StagedWritable
20
+ */
21
+ stage(): StagedWritable<T>;
22
+ /**
23
+ * The function get's called once with the current value and then when the
24
+ * values changes
25
+ *
26
+ * #### Note
27
+ * This does not check for equality like svelte.
28
+ *
29
+ * @return a function which should be called to unsubscribe
30
+ */
31
+ subscribe(fn: (val: T) => void, invalidate?: () => void): () => void;
32
+ /**
33
+ * Either updates the store and calls all subscribers with the value or
34
+ * updates the stateful value if previously toStateful was called
35
+ */
36
+ set(inner: T): void;
37
+ /**
38
+ * If the value was staged, then update the store and call all subscribers with the value
39
+ */
40
+ commit(): void;
41
+ /**
42
+ * Get the current value either staged or not
43
+ */
44
+ get(): T;
45
+ readonly(): Readable<T>;
46
+ readclone<U extends T & CloneableOrPrimitive>(this: StagedWritable<U>): Readable<U>;
47
+ }
48
+ //# sourceMappingURL=StagedWritable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StagedWritable.d.ts","sourceRoot":"","sources":["../../../src/std/stores/StagedWritable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC,MAAM,CAAC,OAAO,OAAO,cAAc,CAAC,CAAC;IACpC,OAAO,CAAC,KAAK,CAAc;IAE3B,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,MAAM,CAAgB;IAE9B;;;;OAIG;gBACS,GAAG,EAAE,CAAC;IAMlB;;OAEG;IACH,QAAQ,IAAI,OAAO;IAInB;;;OAGG;IACH,KAAK,IAAI,cAAc,CAAC,CAAC,CAAC;IAQ1B;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,EAAE,UAAU,CAAC,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAIpE;;;OAGG;IACH,GAAG,CAAC,KAAK,EAAE,CAAC;IASZ;;OAEG;IACH,MAAM;IASN;;OAEG;IACH,GAAG,IAAI,CAAC;IAKR,QAAQ,IAAI,QAAQ,CAAC,CAAC,CAAC;IAIvB,SAAS,CAAC,CAAC,SAAS,CAAC,GAAG,oBAAoB,EAC3C,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,GACrB,QAAQ,CAAC,CAAC,CAAC;CAGd"}