crelte 0.5.12 → 0.5.14

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 (78) hide show
  1. package/dist/blocks/Blocks.d.ts +1 -1
  2. package/dist/blocks/Blocks.d.ts.map +1 -1
  3. package/dist/bodyClass/BodyClass.d.ts +18 -1
  4. package/dist/bodyClass/BodyClass.d.ts.map +1 -1
  5. package/dist/bodyClass/BodyClass.js +21 -2
  6. package/dist/bodyClass/ClientBodyClass.d.ts +7 -2
  7. package/dist/bodyClass/ClientBodyClass.d.ts.map +1 -1
  8. package/dist/bodyClass/ClientBodyClass.js +29 -15
  9. package/dist/bodyClass/ServerBodyClass.d.ts +7 -1
  10. package/dist/bodyClass/ServerBodyClass.d.ts.map +1 -1
  11. package/dist/bodyClass/ServerBodyClass.js +19 -5
  12. package/dist/bodyClass/utils.d.ts +39 -0
  13. package/dist/bodyClass/utils.d.ts.map +1 -0
  14. package/dist/bodyClass/utils.js +84 -0
  15. package/dist/crelte.d.ts.map +1 -1
  16. package/dist/crelte.js +2 -0
  17. package/dist/init/client.js +1 -1
  18. package/dist/init/server.d.ts.map +1 -1
  19. package/dist/init/server.js +1 -0
  20. package/dist/init/shared.d.ts.map +1 -1
  21. package/dist/init/shared.js +3 -0
  22. package/dist/loadData/entry.d.ts +11 -2
  23. package/dist/loadData/entry.d.ts.map +1 -1
  24. package/dist/loadData/entry.js +11 -2
  25. package/dist/queries/Queries.d.ts +3 -0
  26. package/dist/queries/Queries.d.ts.map +1 -1
  27. package/dist/queries/Queries.js +3 -0
  28. package/dist/queries/index.d.ts +22 -1
  29. package/dist/queries/index.d.ts.map +1 -1
  30. package/dist/queries/vars.d.ts +25 -2
  31. package/dist/queries/vars.d.ts.map +1 -1
  32. package/dist/queries/vars.js +42 -1
  33. package/dist/routing/route/BaseRoute.d.ts.map +1 -1
  34. package/dist/routing/route/BaseRoute.js +4 -17
  35. package/dist/server/queries/QueryGqlRoute.d.ts +3 -1
  36. package/dist/server/queries/QueryGqlRoute.d.ts.map +1 -1
  37. package/dist/server/queries/QueryGqlRoute.js +7 -5
  38. package/dist/server/queries/QueryHandleRoute.d.ts +3 -2
  39. package/dist/server/queries/QueryHandleRoute.d.ts.map +1 -1
  40. package/dist/server/queries/QueryHandleRoute.js +4 -2
  41. package/dist/server/queries/queries.d.ts.map +1 -1
  42. package/dist/server/queries/queries.js +12 -2
  43. package/dist/server/queries/routes.d.ts +4 -3
  44. package/dist/server/queries/routes.d.ts.map +1 -1
  45. package/dist/server/queries/routes.js +9 -3
  46. package/dist/std/index.d.ts +1 -0
  47. package/dist/std/index.d.ts.map +1 -1
  48. package/dist/std/index.js +1 -0
  49. package/dist/std/url/index.d.ts +40 -0
  50. package/dist/std/url/index.d.ts.map +1 -0
  51. package/dist/std/url/index.js +65 -0
  52. package/dist/std/url/utils.d.ts +19 -0
  53. package/dist/std/url/utils.d.ts.map +1 -0
  54. package/dist/std/url/utils.js +40 -0
  55. package/dist/vite/index.js +3 -2
  56. package/package.json +5 -1
  57. package/src/blocks/Blocks.ts +1 -1
  58. package/src/bodyClass/BodyClass.ts +25 -3
  59. package/src/bodyClass/ClientBodyClass.ts +37 -20
  60. package/src/bodyClass/ServerBodyClass.ts +28 -7
  61. package/src/bodyClass/utils.ts +118 -0
  62. package/src/crelte.ts +3 -0
  63. package/src/init/client.ts +1 -1
  64. package/src/init/server.ts +1 -0
  65. package/src/init/shared.ts +3 -0
  66. package/src/loadData/entry.ts +12 -2
  67. package/src/queries/Queries.ts +3 -0
  68. package/src/queries/index.ts +30 -1
  69. package/src/queries/vars.ts +58 -3
  70. package/src/routing/route/BaseRoute.ts +8 -22
  71. package/src/server/queries/QueryGqlRoute.ts +20 -4
  72. package/src/server/queries/QueryHandleRoute.ts +5 -2
  73. package/src/server/queries/queries.ts +29 -3
  74. package/src/server/queries/routes.ts +18 -3
  75. package/src/std/index.ts +1 -0
  76. package/src/std/url/index.ts +78 -0
  77. package/src/std/url/utils.ts +48 -0
  78. package/src/vite/index.ts +4 -2
@@ -3,10 +3,17 @@ import QueriesCaching from './QueriesCaching.js';
3
3
  import { QueryVar, vars } from '../../queries/vars.js';
4
4
  import { extractEntry } from '../../loadData/index.js';
5
5
  import { calcKey } from '../../ssr/index.js';
6
- import { CacheIfFn, newError, TransformFn, validateVars } from './routes.js';
6
+ import {
7
+ CacheIfFn,
8
+ newError,
9
+ TransformFn,
10
+ validateVars,
11
+ ValidIfFn,
12
+ } from './routes.js';
7
13
 
8
14
  export type QueryGqlArgs = {
9
15
  vars: Record<string, QueryVar> | null;
16
+ validIfFn: ValidIfFn | null;
10
17
  cacheIfFn: CacheIfFn | null;
11
18
  preventCaching: boolean;
12
19
  transformFn: TransformFn | null;
@@ -17,6 +24,7 @@ export default class QueryGqlRoute {
17
24
  name: string;
18
25
  query: string;
19
26
  vars: Record<string, QueryVar> | null;
27
+ validIfFn: ValidIfFn | null;
20
28
  cacheIfFn: CacheIfFn | null;
21
29
  transformFn: TransformFn | null;
22
30
 
@@ -32,6 +40,7 @@ export default class QueryGqlRoute {
32
40
  this.name = name;
33
41
  this.query = query;
34
42
  this.vars = args.vars;
43
+ this.validIfFn = args.validIfFn;
35
44
  this.cacheIfFn = args.cacheIfFn;
36
45
  this.transformFn = args.transformFn;
37
46
 
@@ -97,10 +106,11 @@ export default class QueryGqlRoute {
97
106
  private async transform(
98
107
  jsonResp: Record<string, any>,
99
108
  vars: Record<string, any>,
109
+ csr: CrelteServerRequest,
100
110
  ): Promise<void> {
101
111
  if (!this.transformFn || !jsonResp.data) return;
102
112
 
103
- const transformed = await this.transformFn(jsonResp.data, vars);
113
+ const transformed = await this.transformFn(jsonResp.data, vars, csr);
104
114
  if (typeof transformed !== 'undefined') jsonResp.data = transformed;
105
115
  }
106
116
 
@@ -111,7 +121,13 @@ export default class QueryGqlRoute {
111
121
  let vars: Record<string, any>;
112
122
  try {
113
123
  const reqVars = await csr.req.json();
114
- vars = validateVars(this.vars, reqVars, caching.router);
124
+ vars = validateVars(
125
+ this.vars,
126
+ reqVars,
127
+ this.validIfFn,
128
+ caching.router,
129
+ );
130
+
115
131
  if ('qName' in vars || 'xCraftSite' in vars)
116
132
  throw new Error(
117
133
  'qName and xCraftSite are reserved variable names',
@@ -195,7 +211,7 @@ export default class QueryGqlRoute {
195
211
  jsonResp = await resp.json();
196
212
  if (!jsonResp || typeof jsonResp !== 'object')
197
213
  throw new Error('invalid json response');
198
- await this.transform(jsonResp, vars);
214
+ await this.transform(jsonResp, vars, csr);
199
215
  } catch (e) {
200
216
  return newError(e, 500);
201
217
  }
@@ -1,20 +1,23 @@
1
1
  import { QueryVar } from '../../queries/vars.js';
2
2
  import CrelteServerRequest from '../CrelteServer.js';
3
3
  import ServerRouter from '../ServerRouter.js';
4
- import { HandleFn, newError, validateVars } from './routes.js';
4
+ import { HandleFn, newError, validateVars, ValidIfFn } from './routes.js';
5
5
 
6
6
  // only internal
7
7
  export default class QueryHandleRoute {
8
8
  name: string;
9
+ validIfFn: ValidIfFn | null;
9
10
  handleFn: HandleFn;
10
11
  vars: Record<string, QueryVar> | null;
11
12
 
12
13
  constructor(
13
14
  name: string,
15
+ validIfFn: ValidIfFn | null,
14
16
  handleFn: HandleFn,
15
17
  vars: Record<string, QueryVar> | null,
16
18
  ) {
17
19
  this.name = name;
20
+ this.validIfFn = validIfFn;
18
21
  this.handleFn = handleFn;
19
22
  this.vars = vars;
20
23
  }
@@ -26,7 +29,7 @@ export default class QueryHandleRoute {
26
29
  let vars: Record<string, any>;
27
30
  try {
28
31
  const reqVars = await csr.req.json();
29
- vars = validateVars(this.vars, reqVars, cs);
32
+ vars = validateVars(this.vars, reqVars, this.validIfFn, cs);
30
33
  } catch (e) {
31
34
  return newError(e, 400);
32
35
  }
@@ -1,6 +1,6 @@
1
1
  import ServerRouter from '../ServerRouter.js';
2
2
  import QueriesCaching from './QueriesCaching.js';
3
- import { CacheIfFn, HandleFn, TransformFn } from './routes.js';
3
+ import { CacheIfFn, HandleFn, TransformFn, ValidIfFn } from './routes.js';
4
4
  import { isQueryVar, QueryVar } from '../../queries/vars.js';
5
5
  import { Platform } from '../platform.js';
6
6
  import QueryHandleRoute from './QueryHandleRoute.js';
@@ -13,6 +13,11 @@ type ModQuery = {
13
13
 
14
14
  type ModTs = {
15
15
  variables?: any;
16
+ // only to hint that its validVars
17
+ validVariables?: any;
18
+ // only to hint that its validVars
19
+ validIf?: any;
20
+ validVars?: any;
16
21
  caching?: any;
17
22
  transform?: any;
18
23
  handle?: any;
@@ -24,6 +29,7 @@ type RouteBuilder = {
24
29
  query: string | null;
25
30
  jsFile: string | null;
26
31
  vars: Record<string, QueryVar> | null;
32
+ validIfFn: ValidIfFn | null;
27
33
  /** corresponds to the caching export */
28
34
  cacheIfFn: CacheIfFn | null;
29
35
  preventCaching: boolean;
@@ -59,6 +65,7 @@ export async function initQueryRoutes(
59
65
  query: null,
60
66
  jsFile: null,
61
67
  vars: null,
68
+ validIfFn: null,
62
69
  cacheIfFn: null,
63
70
  preventCaching: false,
64
71
  transformFn: null,
@@ -87,6 +94,17 @@ export async function initQueryRoutes(
87
94
  routeBuilder.vars = parseVars(mts.variables);
88
95
  }
89
96
 
97
+ if (mts.validVariables || mts.validIf) {
98
+ throw new Error(`use the function validVars in ${filename}`);
99
+ }
100
+
101
+ if (mts.validVars) {
102
+ if (typeof mts.validVars !== 'function') {
103
+ throw new Error('validVars should be a function');
104
+ }
105
+ routeBuilder.validIfFn = mts.validVars;
106
+ }
107
+
90
108
  if (mts.caching) {
91
109
  routeBuilder.cacheIfFn = parseCaching(mts.caching);
92
110
  } else if (typeof mts.caching === 'boolean') {
@@ -108,7 +126,10 @@ export async function initQueryRoutes(
108
126
 
109
127
  for (const [name, rb] of routeBuilders.entries()) {
110
128
  if (rb.query) {
111
- if (rb.handleFn) throw new Error('handle function not supported');
129
+ if (rb.handleFn)
130
+ throw new Error(
131
+ 'cannot have a handle function if a query is present',
132
+ );
112
133
 
113
134
  const route = new QueryGqlRoute(name, rb.query, rb);
114
135
 
@@ -119,7 +140,12 @@ export async function initQueryRoutes(
119
140
  if (rb.cacheIfFn || rb.transformFn || rb.preventCaching)
120
141
  throw new Error('caching or transform not supported');
121
142
 
122
- const route = new QueryHandleRoute(name, rb.handleFn, rb.vars);
143
+ const route = new QueryHandleRoute(
144
+ name,
145
+ rb.validIfFn,
146
+ rb.handleFn,
147
+ rb.vars,
148
+ );
123
149
 
124
150
  router.post('/queries/' + route.name, csr =>
125
151
  route.handle(caching.router, csr),
@@ -4,6 +4,12 @@ import ServerRouter from '../ServerRouter.js';
4
4
 
5
5
  export type CacheIfFn = (response: any, vars: Record<string, any>) => boolean;
6
6
 
7
+ /// Either throw or return a boolean
8
+ export type ValidIfFn = (
9
+ vars: Record<string, any>,
10
+ sr: ServerRouter,
11
+ ) => void | boolean;
12
+
7
13
  /// Anything other than returning undefined will replace the response
8
14
  //
9
15
  // Note that even if you return undefined since the response is by reference
@@ -11,6 +17,7 @@ export type CacheIfFn = (response: any, vars: Record<string, any>) => boolean;
11
17
  export type TransformFn = (
12
18
  response: any,
13
19
  vars: Record<string, any>,
20
+ csr: CrelteServerRequest,
14
21
  ) => void | any | Promise<void | any>;
15
22
 
16
23
  export type HandleFn = (
@@ -19,13 +26,14 @@ export type HandleFn = (
19
26
  ) => Promise<any> | any;
20
27
 
21
28
  /**
22
- * Returns the validated variables if some vars where defined
29
+ * Returns the validated variables if some vars were defined
23
30
  * else just returns all vars
24
31
  */
25
32
  export function validateVars(
26
33
  qvars: Record<string, QueryVar> | null,
27
34
  vars: any,
28
- cs: ServerRouter,
35
+ validIfFn: ValidIfFn | null,
36
+ sr: ServerRouter,
29
37
  ): Record<string, any> {
30
38
  if (!vars || typeof vars !== 'object')
31
39
  throw new Error('expected an object as vars');
@@ -35,7 +43,14 @@ export function validateVars(
35
43
  const nVars: Record<string, any> = {};
36
44
 
37
45
  for (const [k, v] of Object.entries(qvars)) {
38
- nVars[k] = v.validValue(vars[k], cs);
46
+ nVars[k] = v.validValue(vars[k], sr);
47
+ }
48
+
49
+ if (validIfFn) {
50
+ // or throw
51
+ const valid = validIfFn(nVars, sr);
52
+ if (typeof valid === 'boolean' && !valid)
53
+ throw new Error('invalid variables for query');
39
54
  }
40
55
 
41
56
  return nVars;
package/src/std/index.ts CHANGED
@@ -10,6 +10,7 @@
10
10
  * - {@link std/stores}
11
11
  * - {@link std/sync}
12
12
  * - {@link std/rand}
13
+ * - {@link std/url}
13
14
  */
14
15
 
15
16
  /**
@@ -0,0 +1,78 @@
1
+ import { BaseRoute } from '../../routing/index.js';
2
+ import { deleteSearchParam, pathnameEq, searchEq, toUrl } from './utils.js';
3
+
4
+ /**
5
+ * Sets the search params of a URL based on the provided options.
6
+ *
7
+ * If a value is `null`, `undefined`, or an empty string, the corresponding
8
+ * search param will be deleted.
9
+ *
10
+ * #### Example
11
+ * ```js
12
+ * urlWithSearch(entry.url, { p: 1 });
13
+ * // or remove a value
14
+ * urlWithSearch(entry.url, { p: null });
15
+ * ```
16
+ */
17
+ export function urlWithSearch(
18
+ url: BaseRoute | URL | string | null | undefined,
19
+ opts: Record<string, string | number | null | undefined>,
20
+ ): string | null {
21
+ if (!url) return null;
22
+
23
+ url = toUrl(url);
24
+
25
+ for (const [k, v] of Object.entries(opts)) {
26
+ if (!deleteSearchParam(v)) {
27
+ url.searchParams.set(k, v as string);
28
+ } else {
29
+ url.searchParams.delete(k);
30
+ }
31
+ }
32
+
33
+ return url.href;
34
+ }
35
+
36
+ /**
37
+ * Compares two URLs for equality.
38
+ * Normally search and hash are ignored.
39
+ *
40
+ * If either or both url is `null` or `undefined`, the function will return
41
+ * `false`.
42
+ *
43
+ * #### Example
44
+ * ```svelte
45
+ * <script>
46
+ * import { getRoute } from 'crelte';
47
+ *
48
+ * const route = getRoute();
49
+ * </script>
50
+ *
51
+ * <a href={item.url} class:active={urlEq($route, item.url)}>
52
+ * {item.title}
53
+ * </a>
54
+ * ```
55
+ */
56
+ export function urlEq(
57
+ a: BaseRoute | URL | string | null | undefined,
58
+ b: BaseRoute | URL | string | null | undefined,
59
+ opts?: { search?: boolean; hash?: boolean },
60
+ ): boolean {
61
+ if (!a || !b) return false;
62
+
63
+ a = toUrl(a);
64
+ b = toUrl(b);
65
+
66
+ // check origin and pathname
67
+ const baseMatches =
68
+ a.origin === b.origin && pathnameEq(a.pathname, b.pathname);
69
+ if (!baseMatches) return false;
70
+
71
+ // check search
72
+ if (opts?.search && !searchEq(a.searchParams, b.searchParams)) return false;
73
+
74
+ // check hash
75
+ if (opts?.hash && a.hash !== b.hash) return false;
76
+
77
+ return true;
78
+ }
@@ -0,0 +1,48 @@
1
+ import { BaseRoute } from '../../routing/index.js';
2
+
3
+ /**
4
+ * Checks if a search param should be removed.
5
+ * This is the case if the value is `null`, `undefined`, or an empty string.
6
+ */
7
+ export function deleteSearchParam(value: string | number | null | undefined) {
8
+ return (
9
+ typeof value === 'undefined' ||
10
+ value === null ||
11
+ (typeof value === 'string' && value === '')
12
+ );
13
+ }
14
+
15
+ /**
16
+ * Converts a `BaseRoute`, `URL`, or string to a `URL` object.
17
+ */
18
+ export function toUrl(url: BaseRoute | URL | string): URL {
19
+ if (typeof url === 'string') return new URL(url);
20
+
21
+ if (url instanceof BaseRoute) return new URL(url.url);
22
+
23
+ return url;
24
+ }
25
+
26
+ /**
27
+ * Compares two `URLSearchParams` objects for equality.
28
+ */
29
+ export function searchEq(a: URLSearchParams, b: URLSearchParams): boolean {
30
+ if (a.size !== b.size) return false;
31
+
32
+ // Clone to avoid mutating the original objects
33
+ const cloneA = new URLSearchParams(a);
34
+ const cloneB = new URLSearchParams(b);
35
+
36
+ cloneA.sort();
37
+ cloneB.sort();
38
+
39
+ return cloneA.toString() === cloneB.toString();
40
+ }
41
+
42
+ /**
43
+ * Compares two pathnames for equality, ignoring trailing slashes.
44
+ */
45
+ export function pathnameEq(a: string, b: string): boolean {
46
+ // check for trailing slashes
47
+ return a === b || a === b + '/' || a + '/' === b;
48
+ }
package/src/vite/index.ts CHANGED
@@ -180,7 +180,7 @@ export default function crelte(opts?: CrelteOptions): Plugin {
180
180
  publicDir: isSsrBuild ? false : 'public',
181
181
  base: '/',
182
182
  server: {
183
- port: 8080,
183
+ port: config.server?.port ?? 8080,
184
184
  },
185
185
  optimizeDeps: {
186
186
  exclude: ['crelte'],
@@ -338,7 +338,9 @@ async function serveVite(env: EnvData, vite: ViteDevServer) {
338
338
  nReq: Connect.IncomingMessage,
339
339
  res: ServerResponse,
340
340
  ) => {
341
- const protocol = vite.config.server.https ? 'https' : 'http';
341
+ const protocol =
342
+ (nReq.headers['x-forwarded-proto'] as string | undefined) ??
343
+ (vite.config.server.https ? 'https' : 'http');
342
344
  const baseUrl = protocol + '://' + nReq.headers['host'];
343
345
 
344
346
  const req = requestToWebRequest(baseUrl, nReq);