evikit 2.11.1 → 2.13.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/db.js CHANGED
@@ -1,128 +1,128 @@
1
- import { getMetadata, metadata } from "valibot";
2
-
3
- /** @type {typeof import('./db.d.ts').flatten} */
4
- export function flatten(relations) {
5
- return /** @type {any} */ (
6
- Object.fromEntries(
7
- Object.entries(relations).map(([Self, self]) => [
8
- Self,
9
- Object.fromEntries(
10
- Object.values(self)
11
- .map((own) =>
12
- Object.values(own).map((other) =>
13
- Object.values(other).map((its) => [its.name, its]),
14
- ),
15
- )
16
- .flat()
17
- .flat(),
18
- ),
19
- ]),
20
- )
21
- );
22
- }
23
-
24
- export function primary() {
25
- return metadata({ primary: true });
26
- }
27
-
28
- /** @type {typeof import('./db.d.ts').references} */
29
- export function references(references, key) {
30
- return metadata({ key: references.entries[key], references });
31
- }
32
-
33
- /** @type {typeof import('./db.d.ts').relations} */
34
- export function relations(schema) {
35
- return /** @type {any} */ (
36
- Object.fromEntries(
37
- Object.entries(/** @type {any} */ (schema)).map(([Self, self]) => [
38
- Self,
39
- Object.fromEntries(
40
- Object.entries(self.entries)
41
- .map(([Own, own]) => [
42
- Own,
43
- Object.fromEntries(
44
- Object.entries(/** @type {any} */ (schema))
45
- .map(([Other, other]) => [
46
- Other,
47
- Object.fromEntries(
48
- Object.entries(other.entries)
49
- .map(([Its, its]) => {
50
- const ownMetadata =
51
- /** @type {{ key?: string, references: any }} */ (
52
- getMetadata(own)
53
- );
54
-
55
- const itsMetadata =
56
- /** @type {{ key?: string, references: any }} */ (
57
- getMetadata(its)
58
- );
59
- return [
60
- Its,
61
- ownMetadata.key == its &&
62
- other == ownMetadata.references
63
- ? {
64
- Its: Its,
65
- name: rewrite(Self, Own, Other, Its),
66
- Other: Other,
67
- Own: Own,
68
- type: "references",
69
- }
70
- : itsMetadata.key == own &&
71
- self == itsMetadata.references
72
- ? {
73
- Its: Its,
74
- name: rewrite(Self, Own, Other, Its),
75
- Other: Other,
76
- Own: Own,
77
- type: "referencedBy",
78
- }
79
- : undefined,
80
- ];
81
- })
82
- .filter(([, maybeUndefined]) => maybeUndefined),
83
- ),
84
- ])
85
- .filter(([, maybeRecordUndefined]) =>
86
- Object.values(maybeRecordUndefined).some((value) => value),
87
- ),
88
- ),
89
- ])
90
- .filter(([, maybeRecordUndefined]) =>
91
- Object.values(maybeRecordUndefined).some((value) => value),
92
- ),
93
- ),
94
- ]),
95
- )
96
- );
97
- }
98
-
99
- /** @param {string} input */
100
- function capitalize(input) {
101
- return `${input[0]?.toUpperCase()}${input.slice(1)}`;
102
- }
103
-
104
- /**
105
- * @param {string} Self
106
- * @param {string} Own
107
- * @param {string} Other
108
- * @param {string} Its
109
- */
110
- function rewrite(Self, Own, Other, Its) {
111
- return (
112
- // Image.id, Question.imageId -> Image.Question.
113
- Its == `${uncapitalize(Self)}${capitalize(Own)}`
114
- ? Other
115
- : // Quiz.coverId, Image.id -> Quiz.cover.
116
- Own.endsWith(capitalize(Its))
117
- ? Own.slice(0, -Its.length)
118
- : // Image.id, Quiz.coverId -> Image.CoverQuiz.
119
- Its.endsWith(capitalize(Own))
120
- ? `${capitalize(Its.slice(0, -Own.length))}${Other}`
121
- : undefined
122
- );
123
- }
124
-
125
- /** @param {string} input */
126
- function uncapitalize(input) {
127
- return `${input[0]?.toLowerCase()}${input.slice(1)}`;
128
- }
1
+ import { getMetadata, metadata } from "valibot";
2
+
3
+ /** @type {typeof import('./db.d.ts').flatten} */
4
+ export function flatten(relations) {
5
+ return /** @type {any} */ (
6
+ Object.fromEntries(
7
+ Object.entries(relations).map(([Self, self]) => [
8
+ Self,
9
+ Object.fromEntries(
10
+ Object.values(self)
11
+ .map((own) =>
12
+ Object.values(own).map((other) =>
13
+ Object.values(other).map((its) => [its.name, its]),
14
+ ),
15
+ )
16
+ .flat()
17
+ .flat(),
18
+ ),
19
+ ]),
20
+ )
21
+ );
22
+ }
23
+
24
+ export function primary() {
25
+ return metadata({ primary: true });
26
+ }
27
+
28
+ /** @type {typeof import('./db.d.ts').references} */
29
+ export function references(references, key) {
30
+ return metadata({ key: references.entries[key], references });
31
+ }
32
+
33
+ /** @type {typeof import('./db.d.ts').relations} */
34
+ export function relations(schema) {
35
+ return /** @type {any} */ (
36
+ Object.fromEntries(
37
+ Object.entries(/** @type {any} */ (schema)).map(([Self, self]) => [
38
+ Self,
39
+ Object.fromEntries(
40
+ Object.entries(self.entries)
41
+ .map(([Own, own]) => [
42
+ Own,
43
+ Object.fromEntries(
44
+ Object.entries(/** @type {any} */ (schema))
45
+ .map(([Other, other]) => [
46
+ Other,
47
+ Object.fromEntries(
48
+ Object.entries(other.entries)
49
+ .map(([Its, its]) => {
50
+ const ownMetadata =
51
+ /** @type {{ key?: string, references: any }} */ (
52
+ getMetadata(own)
53
+ );
54
+
55
+ const itsMetadata =
56
+ /** @type {{ key?: string, references: any }} */ (
57
+ getMetadata(its)
58
+ );
59
+ return [
60
+ Its,
61
+ ownMetadata.key == its &&
62
+ other == ownMetadata.references
63
+ ? {
64
+ Its: Its,
65
+ name: rewrite(Self, Own, Other, Its),
66
+ Other: Other,
67
+ Own: Own,
68
+ type: "references",
69
+ }
70
+ : itsMetadata.key == own &&
71
+ self == itsMetadata.references
72
+ ? {
73
+ Its: Its,
74
+ name: rewrite(Self, Own, Other, Its),
75
+ Other: Other,
76
+ Own: Own,
77
+ type: "referencedBy",
78
+ }
79
+ : undefined,
80
+ ];
81
+ })
82
+ .filter(([, maybeUndefined]) => maybeUndefined),
83
+ ),
84
+ ])
85
+ .filter(([, maybeRecordUndefined]) =>
86
+ Object.values(maybeRecordUndefined).some((value) => value),
87
+ ),
88
+ ),
89
+ ])
90
+ .filter(([, maybeRecordUndefined]) =>
91
+ Object.values(maybeRecordUndefined).some((value) => value),
92
+ ),
93
+ ),
94
+ ]),
95
+ )
96
+ );
97
+ }
98
+
99
+ /** @param {string} input */
100
+ function capitalize(input) {
101
+ return `${input[0]?.toUpperCase()}${input.slice(1)}`;
102
+ }
103
+
104
+ /**
105
+ * @param {string} Self
106
+ * @param {string} Own
107
+ * @param {string} Other
108
+ * @param {string} Its
109
+ */
110
+ function rewrite(Self, Own, Other, Its) {
111
+ return (
112
+ // Image.id, Question.imageId -> Image.Question.
113
+ Its == `${uncapitalize(Self)}${capitalize(Own)}`
114
+ ? Other
115
+ : // Quiz.coverId, Image.id -> Quiz.cover.
116
+ Own.endsWith(capitalize(Its))
117
+ ? Own.slice(0, -Its.length)
118
+ : // Image.id, Quiz.coverId -> Image.CoverQuiz.
119
+ Its.endsWith(capitalize(Own))
120
+ ? `${capitalize(Its.slice(0, -Own.length))}${Other}`
121
+ : undefined
122
+ );
123
+ }
124
+
125
+ /** @param {string} input */
126
+ function uncapitalize(input) {
127
+ return `${input[0]?.toLowerCase()}${input.slice(1)}`;
128
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "evikit",
3
3
  "description": "Preact/SQLite SSR framework for small web apps",
4
- "version": "2.11.1",
4
+ "version": "2.13.0",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": "./index.js",
@@ -32,15 +32,22 @@
32
32
  },
33
33
  "peerDependencies": {
34
34
  "accept-language": "^3.0.20",
35
+ "esbuild": "^0.28.2",
35
36
  "hoofd": "^1.7.3",
36
37
  "preact": "^10.29.2",
37
38
  "preact-iso": "^2.12.0",
38
39
  "valibot": "^1.4.0"
39
40
  },
41
+ "peerDependenciesMeta": {
42
+ "esbuild": {
43
+ "optional": true
44
+ }
45
+ },
40
46
  "devDependencies": {
41
47
  "@eslint/compat": "^2.1.0",
42
48
  "@eslint/js": "^10.0.1",
43
49
  "@types/node": "^24.13.3",
50
+ "esbuild": "^0.28.2",
44
51
  "eslint": "^10.4.0",
45
52
  "eslint-config-prettier": "^10.1.8",
46
53
  "eslint-plugin-perfectionist": "^5.9.0",
@@ -48,5 +55,8 @@
48
55
  "prettier": "^3.8.3",
49
56
  "typescript": "^6.0.3",
50
57
  "typescript-eslint": "^8.59.4"
58
+ },
59
+ "allowScripts": {
60
+ "esbuild": true
51
61
  }
52
62
  }
package/server.d.ts CHANGED
@@ -29,7 +29,7 @@ export function production({
29
29
  html,
30
30
  prerender,
31
31
  }: {
32
- html: string;
32
+ html?: string;
33
33
  prerender({ lang, url }: { lang: string; url: string }): Promise<{
34
34
  data: object;
35
35
  head: {
package/server.js CHANGED
@@ -4,7 +4,8 @@ import acceptLanguage from "accept-language";
4
4
  import { po } from "gettext-parser";
5
5
  import cluster from "node:cluster";
6
6
  import { createHash } from "node:crypto";
7
- import { readFile } from "node:fs/promises";
7
+ import { existsSync } from "node:fs";
8
+ import { readFile, unlink, writeFile } from "node:fs/promises";
8
9
  import { availableParallelism } from "node:os";
9
10
  import { h } from "preact";
10
11
  import { renderToString } from "preact-render-to-string";
@@ -207,10 +208,104 @@ export function json(output) {
207
208
  };
208
209
  }
209
210
 
211
+ let esbuild = false;
212
+
210
213
  /** @param {{ listen: (port: number, callback: () => void) => { close(): void, on(event: "error", callback: (error: unknown) => void ): void } }} app */
211
- export function listen(app) {
214
+ export async function listen(app) {
215
+ if (esbuild && cluster.isPrimary) {
216
+ let esbuildPort = 0;
217
+
218
+ async function makeHtml() {
219
+ await writeFile(
220
+ "./dist/index.html",
221
+ (await readFile("./index.html", "utf-8"))
222
+ .replace(
223
+ "/index.css",
224
+ "/index.css?" + (await sha256("./dist/index.css")),
225
+ )
226
+ .replace(
227
+ /<script[^>]+><\/script>/,
228
+ '<script src="/src/prerender.js?' +
229
+ (await sha256("./dist/src/prerender.js")) +
230
+ '"></script>' +
231
+ (esbuildPort
232
+ ? '<script>new EventSource("http://localhost:' +
233
+ esbuildPort +
234
+ '/esbuild").addEventListener("change", () => location.reload());</script>'
235
+ : ""),
236
+ ),
237
+ );
238
+ }
239
+
240
+ if (process.argv[2] == "build") {
241
+ const { build } = await import("esbuild");
242
+ if (existsSync("./dist/api.js")) {
243
+ await unlink("./dist/api.js");
244
+ }
245
+ await build({
246
+ bundle: true,
247
+ entryPoints: ["./index.css", "./src/prerender.js"],
248
+ outdir: "./dist",
249
+ });
250
+ await makeHtml();
251
+ return;
252
+ }
253
+
254
+ if (process.argv[2] == "dev" && cluster.isPrimary) {
255
+ const { context } = await import("esbuild");
256
+
257
+ const { watch: watchApi } = await context({
258
+ bundle: true,
259
+ entryPoints: ["./src/api.js"],
260
+ external: ["esbuild"],
261
+ outdir: "./dist",
262
+ platform: "node",
263
+ });
264
+ await watchApi();
265
+
266
+ const { serve: servePrerender, watch: watchPrerender } = await context({
267
+ bundle: true,
268
+ entryPoints: ["./index.css", "./src/prerender.js"],
269
+ outdir: "./dist",
270
+ });
271
+ await watchPrerender();
272
+ ({ port: esbuildPort } = await servePrerender({
273
+ cors: {
274
+ origin:
275
+ process.env["ORIGIN"] ||
276
+ `http://localhost:${Number(process.env["PORT"]) || 5173}`,
277
+ },
278
+ }));
279
+
280
+ let subprocess = cluster.fork();
281
+ let lastHash =
282
+ (await sha256("./dist/api.js")) +
283
+ (await sha256("./dist/index.css")) +
284
+ (await sha256("./dist/src/prerender.js"));
285
+ await makeHtml();
286
+ setInterval(async () => {
287
+ const hash =
288
+ (await sha256("./dist/api.js")) +
289
+ (await sha256("./dist/index.css")) +
290
+ (await sha256("./dist/src/prerender.js"));
291
+ if (hash != lastHash) {
292
+ lastHash = hash;
293
+ await makeHtml();
294
+ subprocess.kill();
295
+ subprocess = cluster.fork();
296
+ }
297
+ }, 1000);
298
+ }
299
+
300
+ await makeHtml();
301
+ }
302
+
212
303
  const port = Number(process.env["PORT"]) || 5173;
213
- if (cluster.isPrimary && parallelism() > 1) {
304
+ if (
305
+ cluster.isPrimary &&
306
+ parallelism() > 1 &&
307
+ (!esbuild || !process.argv[2])
308
+ ) {
214
309
  /** @type {{ on(event: "message", callback: (message: any) => void): void, send(message: any, _: any, options: { keepOpen: boolean }): void }[]} */
215
310
  const forks = [];
216
311
  for (let i = 0; i < parallelism(); i++) {
@@ -226,7 +321,7 @@ export function listen(app) {
226
321
  }
227
322
  });
228
323
  }
229
- } else {
324
+ } else if ((esbuild && !process.argv[2]) || cluster.isPrimary) {
230
325
  const server = app.listen(port, () => {
231
326
  if (cluster.isPrimary || process.env["i"] == "0") {
232
327
  console.log(
@@ -244,14 +339,20 @@ export function listen(app) {
244
339
  }
245
340
  }
246
341
 
247
- /** @param {{ html: string, prerender({ cookie, lang, url }: { cookie?: string | undefined, lang: string, url: string }): Promise<{ data: {}, head: { elements: Set<{ props: { [k: string]: string }, type: string }>, lang: string, title: string }, html: string }> }} props */
342
+ /** @param {{ html?: string, prerender({ cookie, lang, url }: { cookie?: string | undefined, lang: string, url: string }): Promise<{ data: {}, head: { elements: Set<{ props: { [k: string]: string }, type: string }>, lang: string, title: string }, html: string }> }} props */
248
343
  export function production({ html, prerender }) {
344
+ if (!html) {
345
+ esbuild = true;
346
+ }
249
347
  /**
250
348
  * @param {import("node:http").IncomingMessage} req
251
349
  * @param {import("node:http").ServerResponse<import("node:http").IncomingMessage>} res
252
350
  */
253
351
  return async function onRequest(req, res) {
254
352
  try {
353
+ if (!html) {
354
+ html = await readFile("./dist/index.html", "utf-8");
355
+ }
255
356
  const rendered = await prerender({
256
357
  cookie: req.headers.cookie,
257
358
  lang: acceptLanguage.get(req.headers["accept-language"]) || "en",
@@ -271,9 +372,7 @@ export function production({ html, prerender }) {
271
372
  res.end(
272
373
  html
273
374
  .replace(/lang=".+?"/, () => `lang="${rendered.head.lang}"`)
274
- .replace(/<title>.+<\/title>/, () =>
275
- renderToString(h("title", null, rendered.head.title)),
276
- )
375
+ .replace(/<title>.+<\/title>/, "")
277
376
  .replace(/<!--app-head-->[\s\S]+?<body/, (match) =>
278
377
  match
279
378
  .replace(/<link[^>]+>/g, (link) =>
@@ -283,19 +382,20 @@ export function production({ html, prerender }) {
283
382
  )
284
383
  .replace(
285
384
  `<!--app-head-->`,
286
- [...rendered.head.elements.values()]
287
- .map(
288
- ({ props, type }) =>
289
- `<${type} ` +
290
- Object.entries(props)
291
- .map(([name, value]) => `${name}="${value}"`)
292
- .join(" ") +
293
- (type == "script" ? `</${type}>` : " />"),
294
- )
295
- .join(""),
385
+ renderToString(h("title", null, rendered.head.title)) +
386
+ [...rendered.head.elements.values()]
387
+ .map(
388
+ ({ props, type }) =>
389
+ `<${type} ` +
390
+ Object.entries(props)
391
+ .map(([name, value]) => `${name}="${value}"`)
392
+ .join(" ") +
393
+ (type == "script" ? `</${type}>` : " />"),
394
+ )
395
+ .join(""),
296
396
  )
297
397
  .replace(
298
- /(<div id="app">)[\s\S]+<!--app-html-->/,
398
+ /(<div id="app">)[\s\S]*<!--app-html-->/,
299
399
  (_, div) =>
300
400
  div +
301
401
  rendered.html +
@@ -666,3 +766,12 @@ function ArrayOf(input) {
666
766
  function parallelism() {
667
767
  return Number(process.env["PARALLELISM"]) || availableParallelism();
668
768
  }
769
+
770
+ /** @param {string} file */
771
+ async function sha256(file) {
772
+ return existsSync(file)
773
+ ? createHash("sha256")
774
+ .update(await readFile(file))
775
+ .digest("hex")
776
+ : "";
777
+ }
package/sqlite.js CHANGED
@@ -323,7 +323,7 @@ export function sqlite({ pkg, schema }) {
323
323
  delete(where) {
324
324
  if (
325
325
  database
326
- .prepare(`delete from ${table}` + whereQuery({ where }))
326
+ .prepare(`delete from ${table}` + whereQuery(where))
327
327
  .run(...whereValues(where)).changes
328
328
  ) {
329
329
  publish({ table });
@@ -335,21 +335,23 @@ export function sqlite({ pkg, schema }) {
335
335
  return select({ database, flat, join, schema, table });
336
336
  },
337
337
 
338
- /** @param {{ set: Partial<import("valibot").InferOutput<(typeof schema)[typeof table]>>, where: import("./db.d.ts").Where<typeof schema, typeof table> }} props */
339
- update({ set, where }) {
338
+ /** @param {import("./db.d.ts").Where<typeof schema, typeof table> & { set: Partial<import("valibot").InferOutput<(typeof schema)[typeof table]>>, where?: import("./db.d.ts").Where<typeof schema, typeof table> }} query */
339
+ update(query) {
340
340
  if (
341
341
  database
342
342
  .prepare(
343
343
  `update ${table} set\n` +
344
- Object.keys(set)
344
+ Object.keys(query.set)
345
345
  .map((name) => `${name} = ?`)
346
346
  .join(",\n") +
347
- whereQuery({ where }),
347
+ whereQuery(wherePropertyOrSelf(query)),
348
348
  )
349
349
  .run(
350
350
  ...[
351
- ...Object.values(set).map((value) => value ?? null),
352
- ...whereValues(where),
351
+ ...Object.values(query.set).map(
352
+ (value) => value ?? null,
353
+ ),
354
+ ...whereValues(wherePropertyOrSelf(query)),
353
355
  ],
354
356
  ).changes
355
357
  ) {
@@ -391,12 +393,12 @@ export function sqlite({ pkg, schema }) {
391
393
  };
392
394
  }
393
395
 
394
- /** @type {<Schema extends Record<string, import("valibot").ObjectSchema<any, any>>, R extends import("./db.d.ts").Relations<Schema> = import("./db.d.ts").Relations<Schema>, F extends import("./db.d.ts").Flatten<Schema> = import("./db.d.ts").Flatten<Schema>, Table extends keyof F & keyof Schema = keyof F & keyof Schema >(props: { database: DatabaseSync; flat: F; join?: import("./db.d.ts").Join<R, Table> & { limit?: number, offset?: number, order?: import("./db.d.ts").Order<Schema, Table>, where?: import("./db.d.ts").Where<Schema, Table> }; schema: Schema; table: Table; }) => any[]} */
396
+ /** @type {<Schema extends Record<string, import("valibot").ObjectSchema<any, any>>, R extends import("./db.d.ts").Relations<Schema> = import("./db.d.ts").Relations<Schema>, F extends import("./db.d.ts").Flatten<Schema> = import("./db.d.ts").Flatten<Schema>, Table extends keyof F & keyof Schema = keyof F & keyof Schema >(props: { database: DatabaseSync; flat: F; join?: import("./db.d.ts").Join<R, Table> & import("./db.d.ts").Where<Schema, Table> & { limit?: number, offset?: number, order?: import("./db.d.ts").Order<Schema, Table>, where?: import("./db.d.ts").Where<Schema, Table> }; schema: Schema; table: Table; }) => any[]} */
395
397
  function select(props) {
396
398
  ok(typeof props.table == "string");
397
399
  let sql =
398
400
  `select * from ${props.table}` +
399
- whereQuery({ where: props.join?.where }) +
401
+ whereQuery(wherePropertyOrSelf(props.join)) +
400
402
  (props.join?.order
401
403
  ? "\norder by " +
402
404
  (Array.isArray(props.join.order)
@@ -405,7 +407,7 @@ function select(props) {
405
407
  )
406
408
  .flatMap((column) =>
407
409
  Object.entries(column).map(([name, props]) =>
408
- props?.desc ? `${name} desc` : name,
410
+ typeof props == "object" && props?.desc ? `${name} desc` : name,
409
411
  ),
410
412
  )
411
413
  .join(", ")
@@ -469,7 +471,7 @@ function select(props) {
469
471
 
470
472
  const rows = props.database
471
473
  .prepare(sql)
472
- .all(...whereValues(props.join?.where));
474
+ .all(...whereValues(wherePropertyOrSelf(props.join)));
473
475
  if (!(/** @type {any} */ (props.join)?.with)) {
474
476
  for (const row of rows) {
475
477
  for (const name of Object.keys(row)) {
@@ -543,15 +545,28 @@ function select(props) {
543
545
  return state.entities;
544
546
  }
545
547
 
546
- /** @param {{ alias?: string, where: import("./db.js").Where<any, string> | undefined }} props */
547
- function whereQuery({ alias, where }) {
548
+ let deprecatedFound = false;
549
+ /** @param {{ where?: any } | undefined} props */
550
+ function wherePropertyOrSelf(props) {
551
+ if (props?.where) {
552
+ if (!deprecatedFound) {
553
+ deprecatedFound = true;
554
+ console.error(
555
+ "`where: {}` is deprecated, move its properties one level above",
556
+ );
557
+ }
558
+ return props.where;
559
+ }
560
+ return props;
561
+ }
562
+
563
+ /** @param {import("./db.js").Where<any, string> | undefined} where */
564
+ function whereQuery(where) {
548
565
  return (
549
566
  "\nwhere true\n" +
550
567
  Object.entries(where || {})
568
+ .filter(([name]) => !/^(limit|offset|order|set|with)$/.test(name))
551
569
  .map(([name, values]) => {
552
- if (alias) {
553
- name = `${alias}.${name}`;
554
- }
555
570
  return Array.isArray(values)
556
571
  ? `and ${name} in (${values.map(() => "?").join(", ")})`
557
572
  : typeof values == "number" || typeof values == "string"
@@ -579,8 +594,9 @@ function whereQuery({ alias, where }) {
579
594
 
580
595
  /** @param {import("./db.js").Where<any, string> | undefined} where */
581
596
  function whereValues(where) {
582
- return Object.values(where || {})
583
- .flatMap((values) =>
597
+ return Object.entries(where || {})
598
+ .filter(([name]) => !/^(limit|offset|order|set|with)$/.test(name))
599
+ .flatMap(([, values]) =>
584
600
  Array.isArray(values)
585
601
  ? values
586
602
  : typeof values == "number" || typeof values == "string"