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/.woodpecker/test.yaml +38 -38
- package/README.md +38 -7
- package/db.d.ts +272 -265
- package/db.js +128 -128
- package/package.json +11 -1
- package/server.d.ts +1 -1
- package/server.js +128 -19
- package/sqlite.js +34 -18
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.
|
|
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
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 {
|
|
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 (
|
|
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
|
|
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
|
-
|
|
287
|
-
.
|
|
288
|
-
(
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
.
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
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]
|
|
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(
|
|
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
|
|
339
|
-
update(
|
|
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(
|
|
347
|
+
whereQuery(wherePropertyOrSelf(query)),
|
|
348
348
|
)
|
|
349
349
|
.run(
|
|
350
350
|
...[
|
|
351
|
-
...Object.values(set).map(
|
|
352
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
547
|
-
|
|
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.
|
|
583
|
-
.
|
|
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"
|